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:
@@ -19,23 +19,42 @@
|
||||
|
||||
// Form State (Runes)
|
||||
let formData = $state({
|
||||
attention_to: address?.attention_to ?? '',
|
||||
organization_name: address?.organization_name ?? '',
|
||||
line_1: address?.line_1 ?? '',
|
||||
line_2: address?.line_2 ?? '',
|
||||
line_3: address?.line_3 ?? '',
|
||||
city: address?.city ?? '',
|
||||
state_province: address?.state_province ?? '',
|
||||
postal_code: address?.postal_code ?? '',
|
||||
country: address?.country ?? '',
|
||||
// country_name: address?.country_name ?? '', // DO NOT USE - Scott 2026-01-09
|
||||
timezone: address?.timezone ?? '',
|
||||
latitude: address?.latitude ?? '',
|
||||
longitude: address?.longitude ?? '',
|
||||
notes: address?.notes ?? '',
|
||||
enable: address?.enable ?? true,
|
||||
hide: address?.hide ?? false,
|
||||
priority: address?.priority ?? false
|
||||
attention_to: '',
|
||||
organization_name: '',
|
||||
line_1: '',
|
||||
line_2: '',
|
||||
line_3: '',
|
||||
city: '',
|
||||
state_province: '',
|
||||
postal_code: '',
|
||||
country: '',
|
||||
timezone: '',
|
||||
latitude: '',
|
||||
longitude: '',
|
||||
notes: '',
|
||||
enable: true,
|
||||
hide: false,
|
||||
priority: false
|
||||
});
|
||||
|
||||
// Reset form when address prop changes
|
||||
$effect(() => {
|
||||
formData.attention_to = address?.attention_to ?? '';
|
||||
formData.organization_name = address?.organization_name ?? '';
|
||||
formData.line_1 = address?.line_1 ?? '';
|
||||
formData.line_2 = address?.line_2 ?? '';
|
||||
formData.line_3 = address?.line_3 ?? '';
|
||||
formData.city = address?.city ?? '';
|
||||
formData.state_province = address?.state_province ?? '';
|
||||
formData.postal_code = address?.postal_code ?? '';
|
||||
formData.country = address?.country ?? '';
|
||||
formData.timezone = address?.timezone ?? '';
|
||||
formData.latitude = address?.latitude ?? '';
|
||||
formData.longitude = address?.longitude ?? '';
|
||||
formData.notes = address?.notes ?? '';
|
||||
formData.enable = address?.enable ?? true;
|
||||
formData.hide = address?.hide ?? false;
|
||||
formData.priority = address?.priority ?? false;
|
||||
});
|
||||
|
||||
let is_loading = $state(false);
|
||||
|
||||
@@ -19,19 +19,36 @@
|
||||
|
||||
// Form State (Runes)
|
||||
let formData = $state({
|
||||
title: contact?.title ?? '',
|
||||
tagline: contact?.tagline ?? '',
|
||||
email: contact?.email ?? '',
|
||||
phone_mobile: contact?.phone_mobile ?? '',
|
||||
phone_office: contact?.phone_office ?? '',
|
||||
website_url: contact?.website_url ?? '',
|
||||
facebook_url: contact?.facebook_url ?? '',
|
||||
instagram_url: contact?.instagram_url ?? '',
|
||||
linkedin_url: contact?.linkedin_url ?? '',
|
||||
notes: contact?.notes ?? '',
|
||||
enable: contact?.enable ?? true,
|
||||
hide: contact?.hide ?? false,
|
||||
priority: contact?.priority ?? false
|
||||
title: '',
|
||||
tagline: '',
|
||||
email: '',
|
||||
phone_mobile: '',
|
||||
phone_office: '',
|
||||
website_url: '',
|
||||
facebook_url: '',
|
||||
instagram_url: '',
|
||||
linkedin_url: '',
|
||||
notes: '',
|
||||
enable: true,
|
||||
hide: false,
|
||||
priority: false
|
||||
});
|
||||
|
||||
// Reset form when contact prop changes
|
||||
$effect(() => {
|
||||
formData.title = contact?.title ?? '';
|
||||
formData.tagline = contact?.tagline ?? '';
|
||||
formData.email = contact?.email ?? '';
|
||||
formData.phone_mobile = contact?.phone_mobile ?? '';
|
||||
formData.phone_office = contact?.phone_office ?? '';
|
||||
formData.website_url = contact?.website_url ?? '';
|
||||
formData.facebook_url = contact?.facebook_url ?? '';
|
||||
formData.instagram_url = contact?.instagram_url ?? '';
|
||||
formData.linkedin_url = contact?.linkedin_url ?? '';
|
||||
formData.notes = contact?.notes ?? '';
|
||||
formData.enable = contact?.enable ?? true;
|
||||
formData.hide = contact?.hide ?? false;
|
||||
formData.priority = contact?.priority ?? false;
|
||||
});
|
||||
|
||||
let is_loading = $state(false);
|
||||
|
||||
@@ -19,22 +19,42 @@
|
||||
|
||||
// Form State (Runes)
|
||||
let formData = $state({
|
||||
given_name: person?.given_name ?? '',
|
||||
family_name: person?.family_name ?? '',
|
||||
middle_name: person?.middle_name ?? '',
|
||||
prefix: person?.prefix ?? person?.title_names ?? '',
|
||||
suffix: person?.suffix ?? person?.designations ?? '',
|
||||
nickname: person?.informal_name ?? '',
|
||||
professional_title: person?.professional_title ?? '',
|
||||
affiliations: person?.affiliations ?? '',
|
||||
primary_email: person?.primary_email ?? '',
|
||||
phone: person?.phone ?? '',
|
||||
tagline: person?.tagline ?? '',
|
||||
notes: person?.notes ?? '',
|
||||
user_id_random: person?.user_id_random ?? '',
|
||||
enable: person?.enable ?? true,
|
||||
hide: person?.hide ?? false,
|
||||
priority: person?.priority ?? false
|
||||
given_name: '',
|
||||
family_name: '',
|
||||
middle_name: '',
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
nickname: '',
|
||||
professional_title: '',
|
||||
affiliations: '',
|
||||
primary_email: '',
|
||||
phone: '',
|
||||
tagline: '',
|
||||
notes: '',
|
||||
user_id_random: '',
|
||||
enable: true,
|
||||
hide: false,
|
||||
priority: false
|
||||
});
|
||||
|
||||
// Reset form when person prop changes
|
||||
$effect(() => {
|
||||
formData.given_name = person?.given_name ?? '';
|
||||
formData.family_name = person?.family_name ?? '';
|
||||
formData.middle_name = person?.middle_name ?? '';
|
||||
formData.prefix = (person?.prefix ?? person?.title_names) ?? '';
|
||||
formData.suffix = (person?.suffix ?? person?.designations) ?? '';
|
||||
formData.nickname = person?.informal_name ?? '';
|
||||
formData.professional_title = person?.professional_title ?? '';
|
||||
formData.affiliations = person?.affiliations ?? '';
|
||||
formData.primary_email = person?.primary_email ?? '';
|
||||
formData.phone = person?.phone ?? '';
|
||||
formData.tagline = person?.tagline ?? '';
|
||||
formData.notes = person?.notes ?? '';
|
||||
formData.user_id_random = person?.user_id_random ?? '';
|
||||
formData.enable = person?.enable ?? true;
|
||||
formData.hide = person?.hide ?? false;
|
||||
formData.priority = person?.priority ?? false;
|
||||
});
|
||||
|
||||
let is_loading = $state(false);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user