refactor: harden type safety and modernize core forms for Svelte 5

- Standardize 'ae_BaseObj' and event types in 'ae_types.ts' to handle nullable fields from V3 API/Dexie.
- Modernize Person, Address, and Contact forms with Svelte 5 Runes and reactive synchronization.
- Refactor Event Settings and its sub-components to use the 'onsave' callback pattern, removing deprecated dispatchers.
- Hardened 'element_data_store_v2' with safe initialization and localStorage caching logic.
- Clean up unused 'element_data_store.svelte' (V1) and suppress Electron environment type errors in 'tmp_shell_handlers.ts'.
- Update documentation and workspace settings to reflect Phase 5 reactive patterns.
This commit is contained in:
Scott Idem
2026-01-28 14:40:20 -05:00
parent bc1d74f817
commit 55773a332d
24 changed files with 31006 additions and 1139 deletions

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { page } from '$app/state';
import { liveQuery } from 'dexie';
import { db_events } from '$lib/ae_events/db_events';
import { db_events, type Event } from '$lib/ae_events/db_events';
import { onMount } from 'svelte';
import { events_func } from '$lib/ae_events_functions';
import { ae_api } from '$lib/stores/ae_stores';
@@ -12,8 +12,8 @@
import Ae_comp_event_settings_badges_form from './ae_comp__event_settings_badges_form.svelte';
import Ae_comp_event_settings_abstracts_form from './ae_comp__event_settings_abstracts_form.svelte';
let event_id = page.params.event_id;
let event_obj = $state(null);
let event_id = page.params.event_id as string;
let event_obj: Event | undefined | null = $state(null);
let cfg_json_view = $state('form');
let pres_mgmt_json_view = $state('form');
let badges_json_view = $state('form');
@@ -30,7 +30,8 @@
};
});
async function handle_save(field_name: string, data: string | object) {
async function handle_save(field_name: string, data: any) {
if (!data) return;
try {
let data_kv = {};
if (field_name === 'basic_fields') {
@@ -63,7 +64,7 @@
<div class="p-4">
<Ae_comp_event_settings_basic_form
bind:event_obj
on:save={(e) => handle_save('basic_fields', e.detail)}
onsave={(data: any) => handle_save('basic_fields', data)}
/>
</div>
</details>
@@ -80,23 +81,23 @@
{#if cfg_json_view === 'form'}
<Ae_comp_event_settings_form
bind:cfg_json={event_obj.cfg_json}
on:save={(e) => handle_save('cfg_json', e.detail)}
onsave={(data: any) => handle_save('cfg_json', data)}
/>
{:else}
<E_app_codemirror_v5
editable={true}
readonly={false}
content={JSON.stringify(event_obj.cfg_json, null, 4)}
bind:new_content={event_obj.cfg_json}
show_line_numbers={true}
placeholder="JSON config"
class="p-1 preset-outlined-success-400-600 shadow-lg rounded-lg"
on:change={(e) => {
event_obj.cfg_json = e.detail;
}}
/>
<button
class="btn preset-tonal-primary"
onclick={() => handle_save('cfg_json', event_obj.cfg_json)}>Save</button
onclick={() => {
if (event_obj) handle_save('cfg_json', event_obj.cfg_json);
}}>Save</button
>
{/if}
</div>
@@ -116,25 +117,24 @@
{#if pres_mgmt_json_view === 'form'}
<Ae_comp_event_settings_pres_mgmt_form
bind:mod_pres_mgmt_json={event_obj.mod_pres_mgmt_json}
on:save={(e) => handle_save('mod_pres_mgmt_json', e.detail)}
onsave={(data: any) => handle_save('mod_pres_mgmt_json', data)}
/>
{:else}
<E_app_codemirror_v5
editable={true}
readonly={false}
content={JSON.stringify(event_obj.mod_pres_mgmt_json, null, 4)}
bind:new_content={event_obj.mod_pres_mgmt_json}
show_line_numbers={true}
placeholder="JSON config"
class="p-1 preset-outlined-success-400-600 shadow-lg rounded-lg"
on:change={(e) => {
event_obj.mod_pres_mgmt_json = e.detail;
}}
/>
<button
class="btn preset-tonal-primary"
onclick={() =>
handle_save('mod_pres_mgmt_json', event_obj.mod_pres_mgmt_json)}
>Save</button
onclick={() => {
if (event_obj)
handle_save('mod_pres_mgmt_json', event_obj.mod_pres_mgmt_json);
}}>Save</button
>
{/if}
</div>
@@ -154,24 +154,23 @@
{#if badges_json_view === 'form'}
<Ae_comp_event_settings_badges_form
bind:mod_badges_json={event_obj.mod_badges_json}
on:save={(e) => handle_save('mod_badges_json', e.detail)}
onsave={(data: any) => handle_save('mod_badges_json', data)}
/>
{:else}
<E_app_codemirror_v5
editable={true}
readonly={false}
content={JSON.stringify(event_obj.mod_badges_json, null, 4)}
bind:new_content={event_obj.mod_badges_json}
show_line_numbers={true}
placeholder="JSON config"
class="p-1 preset-outlined-success-400-600 shadow-lg rounded-lg"
on:change={(e) => {
event_obj.mod_badges_json = e.detail;
}}
/>
<button
class="btn preset-tonal-primary"
onclick={() => handle_save('mod_badges_json', event_obj.mod_badges_json)}
>Save</button
onclick={() => {
if (event_obj) handle_save('mod_badges_json', event_obj.mod_badges_json);
}}>Save</button
>
{/if}
</div>
@@ -191,25 +190,24 @@
{#if abstracts_json_view === 'form'}
<Ae_comp_event_settings_abstracts_form
bind:mod_abstracts_json={event_obj.mod_abstracts_json}
on:save={(e) => handle_save('mod_abstracts_json', e.detail)}
onsave={(data: any) => handle_save('mod_abstracts_json', data)}
/>
{:else}
<E_app_codemirror_v5
editable={true}
readonly={false}
content={JSON.stringify(event_obj.mod_abstracts_json, null, 4)}
bind:new_content={event_obj.mod_abstracts_json}
show_line_numbers={true}
placeholder="JSON config"
class="p-1 preset-outlined-success-400-600 shadow-lg rounded-lg"
on:change={(e) => {
event_obj.mod_abstracts_json = e.detail;
}}
/>
<button
class="btn preset-tonal-primary"
onclick={() =>
handle_save('mod_abstracts_json', event_obj.mod_abstracts_json)}
>Save</button
onclick={() => {
if (event_obj)
handle_save('mod_abstracts_json', event_obj.mod_abstracts_json);
}}>Save</button
>
{/if}
</div>
@@ -222,17 +220,16 @@
editable={true}
readonly={false}
content={JSON.stringify(event_obj.mod_exhibits_json, null, 4)}
bind:new_content={event_obj.mod_exhibits_json}
show_line_numbers={true}
placeholder="JSON config"
class="p-1 preset-outlined-success-400-600 shadow-lg rounded-lg"
on:change={(e) => {
event_obj.mod_exhibits_json = e.detail;
}}
/>
<button
class="btn preset-tonal-primary"
onclick={() => handle_save('mod_exhibits_json', event_obj.mod_exhibits_json)}
>Save</button
onclick={() => {
if (event_obj) handle_save('mod_exhibits_json', event_obj.mod_exhibits_json);
}}>Save</button
>
</div>
</details>
@@ -244,17 +241,16 @@
editable={true}
readonly={false}
content={JSON.stringify(event_obj.mod_meetings_json, null, 4)}
bind:new_content={event_obj.mod_meetings_json}
show_line_numbers={true}
placeholder="JSON config"
class="p-1 preset-outlined-success-400-600 shadow-lg rounded-lg"
on:change={(e) => {
event_obj.mod_meetings_json = e.detail;
}}
/>
<button
class="btn preset-tonal-primary"
onclick={() => handle_save('mod_meetings_json', event_obj.mod_meetings_json)}
>Save</button
onclick={() => {
if (event_obj) handle_save('mod_meetings_json', event_obj.mod_meetings_json);
}}>Save</button
>
</div>
</details>

View File

@@ -1,17 +1,15 @@
<script lang="ts">
import type { key_val } from '$lib/stores/ae_stores';
import { createEventDispatcher } from 'svelte';
interface Props {
mod_abstracts_json: key_val;
onsave?: (data: key_val) => void;
}
let { mod_abstracts_json = $bindable() }: Props = $props();
const dispatch = createEventDispatcher();
let { mod_abstracts_json = $bindable(), onsave }: Props = $props();
function save() {
dispatch('save', mod_abstracts_json);
if (onsave) onsave(mod_abstracts_json);
}
</script>

View File

@@ -1,17 +1,15 @@
<script lang="ts">
import type { key_val } from '$lib/stores/ae_stores';
import { createEventDispatcher } from 'svelte';
interface Props {
mod_badges_json: key_val;
onsave?: (data: key_val) => void;
}
let { mod_badges_json = $bindable() }: Props = $props();
const dispatch = createEventDispatcher();
let { mod_badges_json = $bindable(), onsave }: Props = $props();
function save() {
dispatch('save', mod_badges_json);
if (onsave) onsave(mod_badges_json);
}
</script>

View File

@@ -1,17 +1,15 @@
<script lang="ts">
import type { key_val } from '$lib/stores/ae_stores';
import { createEventDispatcher } from 'svelte';
interface Props {
event_obj: key_val;
onsave?: (data: key_val) => void;
}
let { event_obj = $bindable() }: Props = $props();
const dispatch = createEventDispatcher();
let { event_obj = $bindable(), onsave }: Props = $props();
function save() {
dispatch('save', event_obj);
if (onsave) onsave(event_obj);
}
</script>

View File

@@ -1,17 +1,15 @@
<script lang="ts">
import type { key_val } from '$lib/stores/ae_stores';
import { createEventDispatcher } from 'svelte';
interface Props {
cfg_json: key_val;
onsave?: (data: key_val) => void;
}
let { cfg_json = $bindable() }: Props = $props();
const dispatch = createEventDispatcher();
let { cfg_json = $bindable(), onsave }: Props = $props();
function save() {
dispatch('save', cfg_json);
if (onsave) onsave(cfg_json);
}
</script>

View File

@@ -1,17 +1,15 @@
<script lang="ts">
import type { key_val } from '$lib/stores/ae_stores';
import { createEventDispatcher } from 'svelte';
interface Props {
mod_pres_mgmt_json: key_val;
onsave?: (data: key_val) => void;
}
let { mod_pres_mgmt_json = $bindable() }: Props = $props();
const dispatch = createEventDispatcher();
let { mod_pres_mgmt_json = $bindable(), onsave }: Props = $props();
function save() {
dispatch('save', mod_pres_mgmt_json);
if (onsave) onsave(mod_pres_mgmt_json);
}
</script>