Implemented offline-first fast-paths and hardened API/Layout resilience. Added reactive offline banner, root error page, and ghost site fallbacks to handle server downtime and connection loss without crashing.
This commit is contained in:
@@ -12,7 +12,7 @@ import { load_ae_obj_li__event_badge_template } from '$lib/ae_events/ae_events__
|
||||
|
||||
const ae_promises: key_val = {};
|
||||
|
||||
// Updated 2026-01-06
|
||||
// Updated 2026-01-16
|
||||
export async function load_ae_obj_id__event({
|
||||
api_cfg,
|
||||
event_id,
|
||||
@@ -38,6 +38,16 @@ export async function load_ae_obj_id__event({
|
||||
console.log(`*** load_ae_obj_id__event() *** event_id=${event_id}`);
|
||||
}
|
||||
|
||||
// Check if offline
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) {
|
||||
if (log_lvl) console.log('Browser is offline. Skipping API and attempting cache load.');
|
||||
ae_promises.load__event_obj = await db_events.event.get(event_id);
|
||||
if (ae_promises.load__event_obj) {
|
||||
return await _handle_nested_loads(ae_promises.load__event_obj, { api_cfg, inc_device_li, inc_location_li, inc_session_li, inc_template_li, log_lvl });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const event_obj_get_result = await api.get_ae_obj_v3({
|
||||
api_cfg: api_cfg,
|
||||
@@ -81,44 +91,52 @@ export async function load_ae_obj_id__event({
|
||||
}
|
||||
}
|
||||
|
||||
if (ae_promises.load__event_obj) {
|
||||
const current_event_id = ae_promises.load__event_obj.event_id || ae_promises.load__event_obj.id;
|
||||
|
||||
if (inc_device_li) {
|
||||
ae_promises.load__event_obj.event_device_obj_li = await load_ae_obj_li__event_device({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
if (inc_location_li) {
|
||||
ae_promises.load__event_obj.event_location_obj_li = await load_ae_obj_li__event_location({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
if (inc_session_li) {
|
||||
ae_promises.load__event_obj.event_session_obj_li = await load_ae_obj_li__event_session({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
if (inc_template_li) {
|
||||
ae_promises.load__event_obj.event_badge_template_obj_li =
|
||||
await load_ae_obj_li__event_badge_template({
|
||||
api_cfg,
|
||||
event_id: current_event_id,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
if (!ae_promises?.load__event_obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ae_promises.load__event_obj;
|
||||
return await _handle_nested_loads(ae_promises.load__event_obj, { api_cfg, inc_device_li, inc_location_li, inc_session_li, inc_template_li, log_lvl });
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared logic for loading nested child collections
|
||||
*/
|
||||
async function _handle_nested_loads(event_obj: any, { api_cfg, inc_device_li, inc_location_li, inc_session_li, inc_template_li, log_lvl }: any) {
|
||||
const current_event_id = event_obj.event_id || event_obj.id;
|
||||
|
||||
if (inc_device_li) {
|
||||
event_obj.event_device_obj_li = await load_ae_obj_li__event_device({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
if (inc_location_li) {
|
||||
event_obj.event_location_obj_li = await load_ae_obj_li__event_location({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
if (inc_session_li) {
|
||||
event_obj.event_session_obj_li = await load_ae_obj_li__event_session({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
if (inc_template_li) {
|
||||
event_obj.event_badge_template_obj_li =
|
||||
await load_ae_obj_li__event_badge_template({
|
||||
api_cfg,
|
||||
event_id: current_event_id,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return event_obj;
|
||||
}
|
||||
|
||||
// Updated 2026-01-06
|
||||
@@ -152,6 +170,16 @@ export async function load_ae_obj_li__event({
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Event[]> {
|
||||
|
||||
// Check if offline
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) {
|
||||
if (log_lvl) console.log('Browser is offline. Skipping API and attempting cache load.');
|
||||
ae_promises.load__event_obj_li = await db_events.event
|
||||
.where('account_id').equals(for_obj_id)
|
||||
.toArray();
|
||||
return ae_promises.load__event_obj_li || [];
|
||||
}
|
||||
|
||||
let promise;
|
||||
|
||||
if (qry_conference !== null) {
|
||||
@@ -548,259 +576,98 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
}
|
||||
|
||||
// Updated 2025-11-13
|
||||
|
||||
export async function process_ae_obj__event_props({
|
||||
|
||||
obj_li,
|
||||
|
||||
log_lvl = 0
|
||||
|
||||
}: {
|
||||
|
||||
obj_li: any[];
|
||||
|
||||
log_lvl?: number;
|
||||
|
||||
}) {
|
||||
|
||||
return _process_generic_props({
|
||||
|
||||
obj_li,
|
||||
|
||||
obj_type: 'event',
|
||||
|
||||
log_lvl,
|
||||
|
||||
specific_processor: (obj) => {
|
||||
|
||||
if (obj.event_code) {
|
||||
|
||||
obj.code = obj.event_code;
|
||||
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This function will process the event config, specifically for presentation management.
|
||||
|
||||
export function sync_config__event_pres_mgmt({
|
||||
|
||||
pres_mgmt_cfg_remote, // This is the remote config that will be compared.
|
||||
|
||||
pres_mgmt_cfg_local, // This is the local config that will be updated.
|
||||
|
||||
pres_mgmt_cfg_remote,
|
||||
pres_mgmt_cfg_local,
|
||||
log_lvl = 0
|
||||
|
||||
}: {
|
||||
|
||||
pres_mgmt_cfg_remote: key_val;
|
||||
|
||||
pres_mgmt_cfg_local: key_val;
|
||||
|
||||
log_lvl?: number;
|
||||
|
||||
}) {
|
||||
|
||||
if (log_lvl) {
|
||||
|
||||
console.log(
|
||||
|
||||
`*** sync_config__event_pres_mgmt() *** pres_mgmt_cfg_remote:`,
|
||||
|
||||
pres_mgmt_cfg_remote
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Deal with things that can not be overridden first:
|
||||
|
||||
// Labels:
|
||||
|
||||
pres_mgmt_cfg_local.label__person_external_id =
|
||||
|
||||
pres_mgmt_cfg_remote?.label__person_external_id ?? 'External ID';
|
||||
|
||||
pres_mgmt_cfg_local.label__presenter_external_id =
|
||||
|
||||
pres_mgmt_cfg_remote?.label__presenter_external_id ?? 'External ID';
|
||||
|
||||
|
||||
|
||||
pres_mgmt_cfg_local.label__session_poc_type =
|
||||
|
||||
pres_mgmt_cfg_remote?.label__session_poc_type ?? 'poc';
|
||||
|
||||
pres_mgmt_cfg_local.label__session_poc_name =
|
||||
|
||||
pres_mgmt_cfg_remote?.label__session_poc_name_short ?? 'POC';
|
||||
|
||||
pres_mgmt_cfg_local.label__session_poc_name =
|
||||
|
||||
pres_mgmt_cfg_remote?.label__session_poc_name ?? 'Point of Contact';
|
||||
|
||||
|
||||
|
||||
// Hide content:
|
||||
|
||||
|
||||
|
||||
pres_mgmt_cfg_local.hide__session_poc = pres_mgmt_cfg_remote?.hide__session_poc ?? false;
|
||||
|
||||
|
||||
|
||||
// Required fields or options (agreements):
|
||||
|
||||
pres_mgmt_cfg_local.require__presenter_agree =
|
||||
|
||||
pres_mgmt_cfg_remote?.require__presenter_agree ?? false; // In use
|
||||
|
||||
pres_mgmt_cfg_remote?.require__presenter_agree ?? false;
|
||||
pres_mgmt_cfg_local.require__session_agree =
|
||||
|
||||
pres_mgmt_cfg_remote?.require__session_agree ?? false; // New and in progress
|
||||
|
||||
|
||||
|
||||
// Show content:
|
||||
|
||||
pres_mgmt_cfg_remote?.require__session_agree ?? false;
|
||||
pres_mgmt_cfg_local.show__copy_access_link =
|
||||
|
||||
pres_mgmt_cfg_remote?.show__copy_access_link ?? false;
|
||||
|
||||
pres_mgmt_cfg_local.show__email_access_link =
|
||||
|
||||
pres_mgmt_cfg_remote?.show__email_access_link ?? false;
|
||||
|
||||
|
||||
|
||||
pres_mgmt_cfg_local.file_purpose_option_kv =
|
||||
|
||||
pres_mgmt_cfg_remote?.file_purpose_option_kv ?? null;
|
||||
|
||||
|
||||
|
||||
// Deal with things that can be overridden:
|
||||
|
||||
|
||||
|
||||
// Locking the config is targeted at the trusted staff level and below. It is more or less ignored at the global manager and super levels. It may be enforced at the staff admin level?
|
||||
|
||||
if (pres_mgmt_cfg_local.lock_config) {
|
||||
|
||||
console.log(`The config should be locked! Forcing the sync!`);
|
||||
|
||||
// This is to forcibly sync the local config with the remote config.
|
||||
|
||||
pres_mgmt_cfg_local.sync_local_config = true;
|
||||
|
||||
} else {
|
||||
|
||||
// Do not override the preference for syncing the local config with the remote config.
|
||||
|
||||
console.log(
|
||||
|
||||
`The config is not locked. Currently set to sync? ${pres_mgmt_cfg_local.sync_local_config}`
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (pres_mgmt_cfg_local?.sync_local_config) {
|
||||
|
||||
if (log_lvl) {
|
||||
|
||||
console.log(`Syncing the local config with the remote config!!!`);
|
||||
|
||||
}
|
||||
|
||||
// Hide content:
|
||||
|
||||
pres_mgmt_cfg_local.hide__location_code =
|
||||
|
||||
pres_mgmt_cfg_remote?.hide__location_code ?? false;
|
||||
|
||||
|
||||
|
||||
pres_mgmt_cfg_local.hide__presentation_code =
|
||||
|
||||
pres_mgmt_cfg_remote?.hide__presentation_code ?? false;
|
||||
|
||||
pres_mgmt_cfg_local.hide__presentation_datetime =
|
||||
|
||||
pres_mgmt_cfg_remote?.hide__presentation_datetime ?? false;
|
||||
|
||||
pres_mgmt_cfg_local.show_content__presentation_description =
|
||||
|
||||
pres_mgmt_cfg_remote?.show_content__presentation_description ?? false;
|
||||
|
||||
|
||||
|
||||
pres_mgmt_cfg_local.hide__presenter_code =
|
||||
|
||||
pres_mgmt_cfg_remote?.hide__presenter_code ?? false;
|
||||
|
||||
pres_mgmt_cfg_local.hide__presenter_biography =
|
||||
|
||||
pres_mgmt_cfg_remote?.hide__presenter_biography ?? false;
|
||||
|
||||
|
||||
|
||||
pres_mgmt_cfg_local.hide__session_code = pres_mgmt_cfg_remote?.hide__session_code ?? false;
|
||||
|
||||
pres_mgmt_cfg_local.hide__session_description =
|
||||
|
||||
pres_mgmt_cfg_remote?.hide__session_description ?? false;
|
||||
|
||||
pres_mgmt_cfg_local.hide__session_location =
|
||||
|
||||
pres_mgmt_cfg_remote?.hide__session_location ?? false;
|
||||
|
||||
pres_mgmt_cfg_local.hide__session_msg = pres_mgmt_cfg_remote?.hide__session_msg ?? false;
|
||||
|
||||
|
||||
|
||||
pres_mgmt_cfg_local.hide__session_poc_profile =
|
||||
|
||||
pres_mgmt_cfg_remote?.hide__session_poc_profile ?? false; // This should still allow the POC name to be shown.
|
||||
|
||||
pres_mgmt_cfg_remote?.hide__session_poc_profile ?? false;
|
||||
pres_mgmt_cfg_local.hide__session_poc_biography =
|
||||
|
||||
pres_mgmt_cfg_remote?.hide__session_poc_biography ?? false; // New and in progress
|
||||
|
||||
pres_mgmt_cfg_remote?.hide__session_poc_biography ?? false;
|
||||
pres_mgmt_cfg_local.hide__session_poc_profile_pic =
|
||||
|
||||
pres_mgmt_cfg_remote?.hide__session_poc_profile_pic ?? false; // New and in progress
|
||||
|
||||
|
||||
|
||||
pres_mgmt_cfg_remote?.hide__session_poc_profile_pic ?? false;
|
||||
pres_mgmt_cfg_local.hide_launcher_link = pres_mgmt_cfg_remote?.hide_launcher_link ?? false;
|
||||
|
||||
pres_mgmt_cfg_local.hide_launcher_link_legacy =
|
||||
|
||||
pres_mgmt_cfg_remote?.hide_launcher_link_legacy ?? false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (log_lvl) {
|
||||
|
||||
console.log(`pres_mgmt_cfg_local:`, pres_mgmt_cfg_local);
|
||||
|
||||
}
|
||||
|
||||
return pres_mgmt_cfg_local;
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user