fix(idaa): fix country/subdivision/timezone dropdowns — switch to in-memory sort
- Country and state/province fields were showing as plain text inputs because liveQuery used orderBy() on non-indexed columns, causing silent Dexie errors that left the store as undefined indefinitely. - Fix: replaced orderBy() with toArray() + in-memory sort across all three lookup types (country, country_subdivision, time_zone). - Sort convention matches Aether backend: sort DESC (higher = first, NULL=0 last), then name ASC — puts priority entries at the top. - Added db_lookups.ts (IDB schema for lookup tables) and updated core__countries, core__country_subdivisions, core__time_zones to IDB-backed SWR pattern. - Affected: archive edit, archive content edit, recovery meeting edit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,65 +1,64 @@
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { api } from '$lib/api/api';
|
||||
import { db_lookups, LOOKUP_TTL_MS } from '$lib/ae_core/db_lookups';
|
||||
|
||||
import { db_core } from '$lib/ae_core/db_core';
|
||||
/**
|
||||
* Country lookup — IDB-backed SWR helper.
|
||||
*
|
||||
* Calling this function triggers a background API refresh if IDB is empty or
|
||||
* older than 24 hours. The function returns immediately without awaiting the
|
||||
* refresh. Components subscribe to db_lookups.lu_country via liveQuery and
|
||||
* receive automatic updates when the refresh completes.
|
||||
*
|
||||
* Updated 2026-03-23 — replaced localStorage pattern with IDB + 24h TTL
|
||||
*/
|
||||
|
||||
const ae_promises: key_val = {};
|
||||
|
||||
// Updated 2024-10-14
|
||||
export async function load_ae_obj_li__country({
|
||||
async function _refresh_lu_country_background({
|
||||
api_cfg,
|
||||
// account_id,
|
||||
enabled = 'enabled',
|
||||
hidden = 'not_hidden',
|
||||
limit = 275, // There are roughly 249 as of 2026-02
|
||||
offset = 0,
|
||||
order_by_li = { sort: 'DESC', english_short_name: 'ASC', alpha_2_code: 'ASC' } as const,
|
||||
params = {},
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
api_cfg: any;
|
||||
// account_id: string,
|
||||
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
|
||||
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: key_val;
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_li__country() ***`);
|
||||
}
|
||||
|
||||
const params_json: key_val = {};
|
||||
|
||||
// console.log('params_json:', params_json);
|
||||
|
||||
ae_promises.load__country_li = await api
|
||||
.get_ae_obj_li_for_lu({
|
||||
api_cfg: api_cfg,
|
||||
if (log_lvl) console.log('*** _refresh_lu_country_background() ***');
|
||||
try {
|
||||
const result = await api.get_ae_obj_li_for_lu({
|
||||
api_cfg,
|
||||
for_lu_type: 'country',
|
||||
enabled: enabled,
|
||||
hidden: hidden,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
params: params,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(function (country_li_get_result) {
|
||||
if (country_li_get_result) {
|
||||
// handle_db_save_ae_obj_li__country({obj_type: 'country', obj_li: country_li_get_result});
|
||||
return country_li_get_result;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('No results returned or failed.', error);
|
||||
enabled: 'enabled',
|
||||
hidden: 'not_hidden',
|
||||
limit: 275,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
console.log('ae_promises.load__country_li:', ae_promises.load__country_li);
|
||||
return ae_promises.load__country_li;
|
||||
if (result?.length) {
|
||||
await db_lookups.lu_country.clear();
|
||||
await db_lookups.lu_country.bulkPut(result);
|
||||
await db_lookups.lu_cache_meta.put({ lu_type: 'country', refreshed_at: Date.now() });
|
||||
if (log_lvl) console.log(`lu_country: saved ${result.length} records to IDB`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('lu_country refresh failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function load_ae_obj_li__country({
|
||||
api_cfg,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
api_cfg: any;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) console.log('*** load_ae_obj_li__country() ***');
|
||||
|
||||
const count = await db_lookups.lu_country.count();
|
||||
const meta = await db_lookups.lu_cache_meta.get('country');
|
||||
const is_stale = !meta || Date.now() - meta.refreshed_at > LOOKUP_TTL_MS;
|
||||
|
||||
if (count === 0 || is_stale) {
|
||||
// Fire-and-forget — liveQuery subscribers receive updates when IDB is written
|
||||
_refresh_lu_country_background({ api_cfg, log_lvl });
|
||||
} else if (log_lvl) {
|
||||
console.log(`lu_country: IDB fresh (${count} records), skipping refresh`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +1,66 @@
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { api } from '$lib/api/api';
|
||||
import { db_lookups, LOOKUP_TTL_MS } from '$lib/ae_core/db_lookups';
|
||||
|
||||
import { db_core } from '$lib/ae_core/db_core';
|
||||
/**
|
||||
* Country subdivision lookup — IDB-backed SWR helper.
|
||||
*
|
||||
* Calling this function triggers a background API refresh if IDB is empty or
|
||||
* older than 24 hours. Components subscribe to db_lookups.lu_country_subdivision
|
||||
* via liveQuery and receive automatic updates when the refresh completes.
|
||||
*
|
||||
* Updated 2026-03-23 — replaced localStorage pattern with IDB + 24h TTL
|
||||
*/
|
||||
|
||||
const ae_promises: key_val = {};
|
||||
|
||||
// Updated 2024-10-14
|
||||
export async function load_ae_obj_li__country_subdivision({
|
||||
async function _refresh_lu_country_subdivision_background({
|
||||
api_cfg,
|
||||
// account_id,
|
||||
enabled = 'enabled',
|
||||
hidden = 'not_hidden',
|
||||
limit = 3500, // There are roughly 3434 as of 2026-02
|
||||
offset = 0,
|
||||
order_by_li = { sort: 'DESC', name: 'ASC', code: 'ASC' } as const,
|
||||
params = {},
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
api_cfg: any;
|
||||
// account_id: string,
|
||||
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
|
||||
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: key_val;
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_li__country_subdivision() ***`);
|
||||
}
|
||||
|
||||
const params_json: key_val = {};
|
||||
|
||||
// console.log('params_json:', params_json);
|
||||
|
||||
ae_promises.load__country_subdivision_li = await api
|
||||
.get_ae_obj_li_for_lu({
|
||||
api_cfg: api_cfg,
|
||||
if (log_lvl) console.log('*** _refresh_lu_country_subdivision_background() ***');
|
||||
try {
|
||||
const result = await api.get_ae_obj_li_for_lu({
|
||||
api_cfg,
|
||||
for_lu_type: 'country_subdivision',
|
||||
enabled: enabled,
|
||||
hidden: hidden,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
params: params,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(function (country_subdivision_li_get_result) {
|
||||
if (country_subdivision_li_get_result) {
|
||||
// handle_db_save_ae_obj_li__country_subdivision({obj_type: 'country_subdivision', obj_li: country_subdivision_li_get_result});
|
||||
return country_subdivision_li_get_result;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('No results returned or failed.', error);
|
||||
enabled: 'enabled',
|
||||
hidden: 'not_hidden',
|
||||
limit: 3500,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
console.log(
|
||||
'ae_promises.load__country_subdivision_li:',
|
||||
ae_promises.load__country_subdivision_li
|
||||
);
|
||||
return ae_promises.load__country_subdivision_li;
|
||||
if (result?.length) {
|
||||
await db_lookups.lu_country_subdivision.clear();
|
||||
await db_lookups.lu_country_subdivision.bulkPut(result);
|
||||
await db_lookups.lu_cache_meta.put({
|
||||
lu_type: 'country_subdivision',
|
||||
refreshed_at: Date.now()
|
||||
});
|
||||
if (log_lvl)
|
||||
console.log(`lu_country_subdivision: saved ${result.length} records to IDB`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('lu_country_subdivision refresh failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function load_ae_obj_li__country_subdivision({
|
||||
api_cfg,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
api_cfg: any;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) console.log('*** load_ae_obj_li__country_subdivision() ***');
|
||||
|
||||
const count = await db_lookups.lu_country_subdivision.count();
|
||||
const meta = await db_lookups.lu_cache_meta.get('country_subdivision');
|
||||
const is_stale = !meta || Date.now() - meta.refreshed_at > LOOKUP_TTL_MS;
|
||||
|
||||
if (count === 0 || is_stale) {
|
||||
_refresh_lu_country_subdivision_background({ api_cfg, log_lvl });
|
||||
} else if (log_lvl) {
|
||||
console.log(`lu_country_subdivision: IDB fresh (${count} records), skipping refresh`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +1,67 @@
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { api } from '$lib/api/api';
|
||||
import { db_lookups, LOOKUP_TTL_MS } from '$lib/ae_core/db_lookups';
|
||||
|
||||
import { db_core } from '$lib/ae_core/db_core';
|
||||
/**
|
||||
* Time zone lookup — IDB-backed SWR helper.
|
||||
*
|
||||
* Fetches priority timezones (only_priority=true, ~72 records). Calling this
|
||||
* function triggers a background API refresh if IDB is empty or older than
|
||||
* 24 hours. Components subscribe to db_lookups.lu_time_zone via liveQuery and
|
||||
* receive automatic updates when the refresh completes.
|
||||
*
|
||||
* Updated 2026-03-23 — replaced $ae_loc + localStorage pattern with IDB + 24h TTL
|
||||
*/
|
||||
|
||||
const ae_promises: key_val = {};
|
||||
|
||||
// Updated 2026-02-20
|
||||
export async function load_ae_obj_li__time_zone({
|
||||
async function _refresh_lu_time_zone_background({
|
||||
api_cfg,
|
||||
// account_id,
|
||||
enabled = 'enabled',
|
||||
hidden = 'not_hidden',
|
||||
limit = 1800, // There are roughly 1780 as of 2026-02
|
||||
offset = 0,
|
||||
// order_by_li = {'priority': 'DESC', 'group': 'ASC', 'sort': 'DESC', 'name': 'ASC'},
|
||||
order_by_li = { priority: 'DESC', sort: 'DESC', name: 'ASC' } as const,
|
||||
params = {},
|
||||
only_priority = false,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
api_cfg: any;
|
||||
// account_id: string,
|
||||
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
|
||||
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: key_val;
|
||||
params?: key_val;
|
||||
only_priority?: boolean;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_li__time_zone() *** only_priority=${only_priority}`);
|
||||
}
|
||||
|
||||
const params_json: key_val = {};
|
||||
|
||||
// console.log('params_json:', params_json);
|
||||
|
||||
ae_promises.load__time_zone_li = await api
|
||||
.get_ae_obj_li_for_lu({
|
||||
api_cfg: api_cfg,
|
||||
if (log_lvl) console.log('*** _refresh_lu_time_zone_background() ***');
|
||||
try {
|
||||
const result = await api.get_ae_obj_li_for_lu({
|
||||
api_cfg,
|
||||
for_lu_type: 'time_zone',
|
||||
enabled: enabled,
|
||||
hidden: hidden,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
order_by_li: order_by_li,
|
||||
params: params,
|
||||
only_priority: only_priority,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(function (time_zone_li_get_result) {
|
||||
if (time_zone_li_get_result) {
|
||||
// handle_db_save_ae_obj_li__time_zone({obj_type: 'time_zone', obj_li: time_zone_li_get_result});
|
||||
return time_zone_li_get_result;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('No results returned or failed.', error);
|
||||
enabled: 'enabled',
|
||||
hidden: 'not_hidden',
|
||||
only_priority: true, // ~72 priority timezone records
|
||||
limit: 1800,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
console.log('ae_promises.load__time_zone_li:', ae_promises.load__time_zone_li);
|
||||
return ae_promises.load__time_zone_li;
|
||||
if (result?.length) {
|
||||
await db_lookups.lu_time_zone.clear();
|
||||
await db_lookups.lu_time_zone.bulkPut(result);
|
||||
await db_lookups.lu_cache_meta.put({
|
||||
lu_type: 'time_zone',
|
||||
refreshed_at: Date.now()
|
||||
});
|
||||
if (log_lvl) console.log(`lu_time_zone: saved ${result.length} records to IDB`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('lu_time_zone refresh failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function load_ae_obj_li__time_zone({
|
||||
api_cfg,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
api_cfg: any;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) console.log('*** load_ae_obj_li__time_zone() ***');
|
||||
|
||||
const count = await db_lookups.lu_time_zone.count();
|
||||
const meta = await db_lookups.lu_cache_meta.get('time_zone');
|
||||
const is_stale = !meta || Date.now() - meta.refreshed_at > LOOKUP_TTL_MS;
|
||||
|
||||
if (count === 0 || is_stale) {
|
||||
_refresh_lu_time_zone_background({ api_cfg, log_lvl });
|
||||
} else if (log_lvl) {
|
||||
console.log(`lu_time_zone: IDB fresh (${count} records), skipping refresh`);
|
||||
}
|
||||
}
|
||||
|
||||
81
src/lib/ae_core/db_lookups.ts
Normal file
81
src/lib/ae_core/db_lookups.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import Dexie, { type Table } from 'dexie';
|
||||
|
||||
/**
|
||||
* Lookup DB — IDB-backed cache for V3 Uniform Lookup System reference data.
|
||||
*
|
||||
* These tables store the deduplicated, priority-ranked list returned by
|
||||
* GET /v3/lookup/{lu_type}/list. Data is refreshed automatically on a 24-hour
|
||||
* TTL via the core__*.ts load helpers; components subscribe via liveQuery.
|
||||
*
|
||||
* Updated 2026-03-23
|
||||
*/
|
||||
|
||||
export interface LuCountry {
|
||||
id: number;
|
||||
group: string; // dedup key = alpha_2_code (e.g. "US")
|
||||
alpha_2_code: string;
|
||||
name: string;
|
||||
english_short_name?: string;
|
||||
name_override?: string;
|
||||
enable?: number;
|
||||
hide?: number;
|
||||
priority?: number;
|
||||
sort?: number;
|
||||
account_id?: number | null;
|
||||
[key: string]: unknown; // allow extra fields from API without TS errors
|
||||
}
|
||||
|
||||
export interface LuCountrySubdivision {
|
||||
id: number;
|
||||
group: string; // dedup key = code (e.g. "US-NY")
|
||||
code: string;
|
||||
name: string;
|
||||
country_alpha_2_code?: string;
|
||||
name_override?: string;
|
||||
enable?: number;
|
||||
hide?: number;
|
||||
priority?: number;
|
||||
sort?: number;
|
||||
account_id?: number | null;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface LuTimeZone {
|
||||
id: number;
|
||||
group: string; // dedup key = name (IANA identifier, e.g. "US/Eastern")
|
||||
name: string;
|
||||
name_override?: string; // display label override; prefer this over name when set
|
||||
enable?: number;
|
||||
hide?: number;
|
||||
priority?: number;
|
||||
sort?: number;
|
||||
account_id?: number | null;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface LuCacheMeta {
|
||||
lu_type: 'country' | 'country_subdivision' | 'time_zone';
|
||||
refreshed_at: number; // Unix timestamp ms — used for 24h TTL check
|
||||
}
|
||||
|
||||
class LookupsDexie extends Dexie {
|
||||
lu_country!: Table<LuCountry>;
|
||||
lu_country_subdivision!: Table<LuCountrySubdivision>;
|
||||
lu_time_zone!: Table<LuTimeZone>;
|
||||
lu_cache_meta!: Table<LuCacheMeta>;
|
||||
|
||||
constructor() {
|
||||
super('ae_lookups_db');
|
||||
this.version(1).stores({
|
||||
lu_country: 'id, alpha_2_code, group',
|
||||
lu_country_subdivision: 'id, code, country_alpha_2_code, group',
|
||||
lu_time_zone: 'id, name, group',
|
||||
lu_cache_meta: 'lu_type'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const db_lookups = new LookupsDexie();
|
||||
|
||||
/** 24-hour TTL in milliseconds */
|
||||
export const LOOKUP_TTL_MS = 24 * 60 * 60 * 1000;
|
||||
@@ -7,6 +7,8 @@
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { core_func } from '$lib/ae_core/ae_core_functions';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db_lookups } from '$lib/ae_core/db_lookups';
|
||||
import {
|
||||
ae_snip,
|
||||
ae_loc,
|
||||
@@ -106,56 +108,21 @@
|
||||
);
|
||||
}
|
||||
|
||||
let lu_time_zone_list: any = $state(
|
||||
localStorage.getItem('lu_time_zone_list')
|
||||
? JSON.parse(localStorage.getItem('lu_time_zone_list') as string)
|
||||
: []
|
||||
// Timezone lookup — reactive IDB query; background refresh handled by liveQuery + TTL
|
||||
// Sort: sort DESC (higher = first, NULL=0 last), then name ASC — matches Aether backend convention.
|
||||
const lq__lu_time_zone = liveQuery(() =>
|
||||
db_lookups.lu_time_zone.toArray().then(arr =>
|
||||
arr.sort((a, b) => {
|
||||
const s_diff = Number(b['sort'] ?? 0) - Number(a['sort'] ?? 0);
|
||||
if (s_diff !== 0) return s_diff;
|
||||
return (a.name ?? '').localeCompare(b.name ?? '');
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
onMount(() => {
|
||||
$ae_loc.lu_time_zone_list = [];
|
||||
// $ae_loc.lu_time_zone_list = [];
|
||||
// lu_time_zone_list = [];
|
||||
if (lu_time_zone_list && lu_time_zone_list.length > 0) {
|
||||
// console.log('Already have time zone list!', lu_time_zone_list);
|
||||
} else {
|
||||
console.log('No time zone list');
|
||||
|
||||
let lu_time_zone_li_get_promise = core_func
|
||||
.load_ae_obj_li__time_zone({
|
||||
api_cfg: $ae_api,
|
||||
only_priority: true,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(function (lu_time_zone_li_get_result) {
|
||||
/* We need to save the time zone list to localStore */
|
||||
if (lu_time_zone_li_get_result) {
|
||||
lu_time_zone_list = lu_time_zone_li_get_result;
|
||||
localStorage.setItem(
|
||||
'lu_time_zone_list',
|
||||
JSON.stringify(lu_time_zone_li_get_result)
|
||||
);
|
||||
if (log_lvl) {
|
||||
console.log(`Time zone list:`, lu_time_zone_list);
|
||||
}
|
||||
} else {
|
||||
console.log(`No time zones returned!`);
|
||||
// $ae_loc.lu_time_zone_list = [];
|
||||
}
|
||||
|
||||
if (lu_time_zone_li_get_result) {
|
||||
lu_time_zone_list = lu_time_zone_li_get_result;
|
||||
console.log(`Time zone list:`, lu_time_zone_list);
|
||||
console.log(lu_time_zone_list[0]);
|
||||
console.log(lu_time_zone_list[10]);
|
||||
} else {
|
||||
console.log(`No time zones returned!`);
|
||||
lu_time_zone_list = [];
|
||||
}
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('No results returned or failed.', error);
|
||||
});
|
||||
}
|
||||
// Trigger background IDB refresh if stale/empty; liveQuery reacts automatically
|
||||
core_func.load_ae_obj_li__time_zone({ api_cfg: $ae_api, log_lvl });
|
||||
});
|
||||
|
||||
function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||
@@ -873,7 +840,7 @@
|
||||
<fieldset class="flex_row flex_gap_md flex_justify_around">
|
||||
<label for="original_timezone"
|
||||
>Original Timezone
|
||||
{#if lu_time_zone_list}
|
||||
{#if ($lq__lu_time_zone ?? []).length}
|
||||
<select
|
||||
id="original_timezone"
|
||||
name="original_timezone"
|
||||
@@ -886,7 +853,7 @@
|
||||
title="Select the original timezone"
|
||||
>
|
||||
<option value="">-- None --</option>
|
||||
{#each lu_time_zone_list as lu_timezone (lu_timezone.name)}
|
||||
{#each ($lq__lu_time_zone ?? []) as lu_timezone (lu_timezone.name)}
|
||||
<option value={lu_timezone.name}>
|
||||
{lu_timezone.name}
|
||||
</option>
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { core_func } from '$lib/ae_core/ae_core_functions';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db_lookups } from '$lib/ae_core/db_lookups';
|
||||
import {
|
||||
ae_snip,
|
||||
ae_loc,
|
||||
@@ -44,56 +46,21 @@
|
||||
let notes_changed = $state(false);
|
||||
let disable_submit_btn = true;
|
||||
|
||||
let lu_time_zone_list: any = $state(
|
||||
localStorage.getItem('lu_time_zone_list')
|
||||
? JSON.parse(localStorage.getItem('lu_time_zone_list') as string)
|
||||
: []
|
||||
// Timezone lookup — reactive IDB query; background refresh handled by liveQuery + TTL
|
||||
// Sort: sort DESC (higher = first, NULL=0 last), then name ASC — matches Aether backend convention.
|
||||
const lq__lu_time_zone = liveQuery(() =>
|
||||
db_lookups.lu_time_zone.toArray().then(arr =>
|
||||
arr.sort((a, b) => {
|
||||
const s_diff = Number(b['sort'] ?? 0) - Number(a['sort'] ?? 0);
|
||||
if (s_diff !== 0) return s_diff;
|
||||
return (a.name ?? '').localeCompare(b.name ?? '');
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
onMount(() => {
|
||||
$ae_loc.lu_time_zone_list = [];
|
||||
// $ae_loc.lu_time_zone_list = [];
|
||||
// lu_time_zone_list = [];
|
||||
if (lu_time_zone_list && lu_time_zone_list.length > 0) {
|
||||
// console.log('Already have time zone list!', lu_time_zone_list);
|
||||
} else {
|
||||
console.log('No time zone list');
|
||||
|
||||
let lu_time_zone_li_get_promise = core_func
|
||||
.load_ae_obj_li__time_zone({
|
||||
api_cfg: $ae_api,
|
||||
only_priority: true,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(function (lu_time_zone_li_get_result) {
|
||||
/* We need to save the time zone list to localStore */
|
||||
if (lu_time_zone_li_get_result) {
|
||||
lu_time_zone_list = lu_time_zone_li_get_result;
|
||||
localStorage.setItem(
|
||||
'lu_time_zone_list',
|
||||
JSON.stringify(lu_time_zone_li_get_result)
|
||||
);
|
||||
if (log_lvl) {
|
||||
console.log(`Time zone list:`, lu_time_zone_list);
|
||||
}
|
||||
} else {
|
||||
console.log(`No time zones returned!`);
|
||||
// $ae_loc.lu_time_zone_list = [];
|
||||
}
|
||||
|
||||
if (lu_time_zone_li_get_result) {
|
||||
lu_time_zone_list = lu_time_zone_li_get_result;
|
||||
console.log(`Time zone list:`, lu_time_zone_list);
|
||||
console.log(lu_time_zone_list[0]);
|
||||
console.log(lu_time_zone_list[10]);
|
||||
} else {
|
||||
console.log(`No time zones returned!`);
|
||||
lu_time_zone_list = [];
|
||||
}
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('No results returned or failed.', error);
|
||||
});
|
||||
}
|
||||
// Trigger background IDB refresh if stale/empty; liveQuery reacts automatically
|
||||
core_func.load_ae_obj_li__time_zone({ api_cfg: $ae_api, log_lvl });
|
||||
});
|
||||
|
||||
function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||
@@ -406,7 +373,7 @@
|
||||
<fieldset class="flex_row flex_gap_md flex_justify_around">
|
||||
<label for="original_timezone"
|
||||
>Original Timezone
|
||||
{#if lu_time_zone_list}
|
||||
{#if ($lq__lu_time_zone ?? []).length}
|
||||
<select
|
||||
name="original_timezone"
|
||||
id="original_timezone"
|
||||
@@ -418,7 +385,7 @@
|
||||
title="Select the original timezone"
|
||||
>
|
||||
<option value="">-- None --</option>
|
||||
{#each lu_time_zone_list as lu_timezone (lu_timezone.name)}
|
||||
{#each ($lq__lu_time_zone ?? []) as lu_timezone (lu_timezone.name)}
|
||||
<option value={lu_timezone.name}>
|
||||
{lu_timezone.name}
|
||||
</option>
|
||||
|
||||
@@ -190,14 +190,35 @@
|
||||
// Lookup lists — reactive IDB queries (SWR via db_lookups + liveQuery)
|
||||
// Data persists in IndexedDB with a 24h TTL; onMount triggers a background
|
||||
// refresh if IDB is empty or stale. No localStorage or $ae_loc involved.
|
||||
// Note: orderBy() requires a declared Dexie index. For fields not in the schema index,
|
||||
// use toArray() + in-memory sort instead to avoid a silent liveQuery error.
|
||||
// Sort convention matches the Aether backend: sort DESC (higher = first, NULL=0 last), then name ASC.
|
||||
const lq__lu_country = liveQuery(() =>
|
||||
db_lookups.lu_country.orderBy('english_short_name').toArray()
|
||||
db_lookups.lu_country.toArray().then(arr =>
|
||||
arr.sort((a, b) => {
|
||||
const s_diff = Number(b['sort'] ?? 0) - Number(a['sort'] ?? 0);
|
||||
if (s_diff !== 0) return s_diff;
|
||||
return (a.english_short_name ?? a.name ?? '').localeCompare(b.english_short_name ?? b.name ?? '');
|
||||
})
|
||||
)
|
||||
);
|
||||
const lq__lu_country_subdivision = liveQuery(() =>
|
||||
db_lookups.lu_country_subdivision.orderBy('name').toArray()
|
||||
db_lookups.lu_country_subdivision.toArray().then(arr =>
|
||||
arr.sort((a, b) => {
|
||||
const s_diff = Number(b['sort'] ?? 0) - Number(a['sort'] ?? 0);
|
||||
if (s_diff !== 0) return s_diff;
|
||||
return (a.name ?? '').localeCompare(b.name ?? '');
|
||||
})
|
||||
)
|
||||
);
|
||||
const lq__lu_time_zone = liveQuery(() =>
|
||||
db_lookups.lu_time_zone.orderBy('name').toArray()
|
||||
db_lookups.lu_time_zone.toArray().then(arr =>
|
||||
arr.sort((a, b) => {
|
||||
const s_diff = Number(b['sort'] ?? 0) - Number(a['sort'] ?? 0);
|
||||
if (s_diff !== 0) return s_diff;
|
||||
return (a.name ?? '').localeCompare(b.name ?? '');
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
onMount(() => {
|
||||
|
||||
Reference in New Issue
Block a user