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:
Scott Idem
2026-01-16 16:41:32 -05:00
parent 8b611e7875
commit a10accfaaf
14 changed files with 536 additions and 564 deletions

View File

@@ -11,10 +11,11 @@ import { load_ae_obj_li__event_session } from './ae_events__event_session';
const ae_promises: key_val = {};
// Updated 2025-05-23
// Updated 2026-01-16
export async function load_ae_obj_id__event_location({
api_cfg,
event_location_id,
inc_device_li = false,
inc_file_li = false,
inc_session_li = false,
try_cache = true,
@@ -22,6 +23,7 @@ export async function load_ae_obj_id__event_location({
}: {
api_cfg: any;
event_location_id: string;
inc_device_li?: boolean;
inc_file_li?: boolean;
inc_session_li?: boolean;
try_cache?: boolean;
@@ -35,6 +37,16 @@ export async function load_ae_obj_id__event_location({
const params = {};
// 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_location_obj = await db_events.location.get(event_location_id);
if (ae_promises.load__event_location_obj) {
return await _handle_nested_loads(ae_promises.load__event_location_obj, { api_cfg, inc_device_li, inc_file_li, inc_session_li, try_cache, log_lvl });
}
return null;
}
try {
ae_promises.load__event_location_obj = await api
.get_ae_obj_id_crud({
@@ -78,19 +90,31 @@ export async function load_ae_obj_id__event_location({
}
}
if (log_lvl) {
console.log('ae_promises.load__event_location_obj:', ae_promises.load__event_location_obj);
}
if (!ae_promises?.load__event_location_obj) {
return null;
}
const current_location_id = ae_promises.load__event_location_obj.event_location_id || ae_promises.load__event_location_obj.id;
return await _handle_nested_loads(ae_promises.load__event_location_obj, { api_cfg, inc_device_li, inc_file_li, inc_session_li, try_cache, log_lvl });
}
/**
* Helper to handle nested collection loads for a location
*/
async function _handle_nested_loads(location_obj: any, { api_cfg, inc_device_li, inc_file_li, inc_session_li, try_cache, log_lvl }: any) {
const current_location_id = location_obj.event_location_id || location_obj.id;
if (inc_device_li) {
location_obj.event_device_obj_li = await load_ae_obj_li__event_device({
api_cfg: api_cfg,
for_obj_type: 'event_location',
for_obj_id: current_location_id,
log_lvl: log_lvl
});
}
if (inc_file_li) {
// Load the files for the location
ae_promises.load__event_location_obj.event_file_li = await load_ae_obj_li__event_file({
location_obj.event_file_li = await load_ae_obj_li__event_file({
api_cfg: api_cfg,
for_obj_type: 'event_location',
for_obj_id: current_location_id,
@@ -103,7 +127,7 @@ export async function load_ae_obj_id__event_location({
if (inc_session_li) {
// Load the sessions for the location
ae_promises.load__event_location_obj.event_session_li = await load_ae_obj_li__event_session({
location_obj.event_session_li = await load_ae_obj_li__event_session({
api_cfg: api_cfg,
for_obj_type: 'event_location',
for_obj_id: current_location_id,
@@ -114,7 +138,7 @@ export async function load_ae_obj_id__event_location({
});
}
return ae_promises.load__event_location_obj;
return location_obj;
}
// Updated 2025-05-23
@@ -164,6 +188,20 @@ export async function load_ae_obj_li__event_location({
const params_json: key_val = {};
// 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_location_obj_li = await db_events.location
.where('event_id').equals(for_obj_id)
.toArray();
if (ae_promises.load__event_location_obj_li) {
for (let i = 0; i < ae_promises.load__event_location_obj_li.length; i++) {
await _handle_nested_loads(ae_promises.load__event_location_obj_li[i], { api_cfg, inc_device_li, inc_file_li, inc_session_li, try_cache, log_lvl });
}
}
return ae_promises.load__event_location_obj_li || [];
}
try {
ae_promises.load__event_location_obj_li = await api
.get_ae_obj_li_for_obj_id_crud_v2({
@@ -220,54 +258,8 @@ export async function load_ae_obj_li__event_location({
}
if (ae_promises.load__event_location_obj_li) {
if (inc_device_li) {
for (let i = 0; i < ae_promises.load__event_location_obj_li.length; i++) {
const event_location_obj = ae_promises.load__event_location_obj_li[i];
const current_location_id = event_location_obj.event_location_id || event_location_obj.id;
event_location_obj.event_device_obj_li = await load_ae_obj_li__event_device({
api_cfg: api_cfg,
for_obj_type: 'event_location',
for_obj_id: current_location_id,
params: { qry__enabled: enabled, qry__limit: limit },
try_cache: try_cache,
log_lvl: log_lvl
});
}
}
if (inc_file_li) {
for (let i = 0; i < ae_promises.load__event_location_obj_li.length; i++) {
const event_location_obj = ae_promises.load__event_location_obj_li[i];
const current_location_id = event_location_obj.event_location_id || event_location_obj.id;
event_location_obj.event_file_li = await load_ae_obj_li__event_file({
api_cfg: api_cfg,
for_obj_type: 'event_location',
for_obj_id: current_location_id,
enabled: enabled,
limit: limit,
try_cache: try_cache,
log_lvl: log_lvl
});
}
}
if (inc_session_li) {
for (let i = 0; i < ae_promises.load__event_location_obj_li.length; i++) {
const event_location_obj = ae_promises.load__event_location_obj_li[i];
const current_location_id = event_location_obj.event_location_id || event_location_obj.id;
event_location_obj.event_session_li = await load_ae_obj_li__event_session({
api_cfg: api_cfg,
for_obj_type: 'event_location',
for_obj_id: current_location_id,
enabled: enabled,
limit: limit,
try_cache: try_cache,
log_lvl: log_lvl
});
}
for (let i = 0; i < ae_promises.load__event_location_obj_li.length; i++) {
await _handle_nested_loads(ae_promises.load__event_location_obj_li[i], { api_cfg, inc_device_li, inc_file_li, inc_session_li, try_cache, log_lvl });
}
}