diff --git a/src/lib/elements/element_data_store.svelte b/src/lib/elements/element_data_store.svelte index 38724cd1..1a085036 100644 --- a/src/lib/elements/element_data_store.svelte +++ b/src/lib/elements/element_data_store.svelte @@ -72,8 +72,28 @@ let { // Local reactive state let trigger: null | string = $state(null); let draft_value = $state(''); +let draft_name = $state(''); +let draft_code = $state(''); +let draft_type = $state(''); +let draft_use_account_id = $state(false); let html_edit_mode = $state<'source' | 'visual'>('source'); +// Change detection derived from draft vs current LiveQuery object +let has_changes = $derived.by(() => { + const entry = $lq__ds_obj as ae_DataStore | null; + if (!entry) return true; // Treat new record as having changes + + const current_val = entry.type === 'json' + ? (typeof entry.json === 'string' ? entry.json : JSON.stringify(entry.json, null, 2)) + : (entry.text || entry.html || ''); + + return draft_value !== current_val || + draft_name !== (entry.name || '') || + draft_code !== (entry.code || '') || + draft_type !== (entry.type || 'text') || + draft_use_account_id !== (!!entry.account_id); +}); + // Dexie LiveQuery for data store let lq__ds_obj = $derived( liveQuery(async () => { @@ -110,6 +130,23 @@ let lq__ds_obj = $derived( }) ); +/** + * reset_drafts: Resets all draft fields to the current object's values. + * Called when the live data changes OR when the editor is closed/cancelled. + */ +function reset_drafts() { + const entry = $lq__ds_obj as ae_DataStore | null; + if (!entry) return; + + draft_name = entry.name || ''; + draft_code = entry.code || ''; + draft_type = entry.type || 'text'; + draft_use_account_id = !!entry.account_id; + draft_value = entry.type === 'json' + ? (typeof entry.json === 'string' ? entry.json : JSON.stringify(entry.json, null, 2)) + : (entry.text || entry.html || ''); +} + // Sync status and bound props when the live data changes $effect(() => { const entry = $lq__ds_obj as ae_DataStore | null; @@ -120,16 +157,30 @@ $effect(() => { if (ds_type === 'sql') { val_sql = entry.text || entry.html || null; } - // Initialize draft_value when not editing + // Initialize draft values when not editing if (!show_edit) { - draft_value = entry.type === 'json' - ? (typeof entry.json === 'string' ? entry.json : JSON.stringify(entry.json, null, 2)) - : (entry.text || entry.html || ''); + reset_drafts(); } } }); }); +// Reset draft values when the editor is closed (discard changes) +$effect(() => { + if (!show_edit) { + untrack(() => reset_drafts()); + } +}); + +// Reset submit status when opening the editor +$effect(() => { + if (show_edit) { + untrack(() => { + $ae_sess.ds.submit_status = 'idle'; + }); + } +}); + // Context Change Guard $effect(() => { void for_id; void for_type; void ds_code; @@ -204,25 +255,16 @@ async function load_data_store() { } async function handle_submit_form(event: Event) { - const target = event.target as HTMLFormElement; $ae_sess.ds.submit_status = 'processing'; - const form_data = new FormData(target); - const data_store_di = ae_util.extract_prefixed_form_data({ - prefix: null, - form_data, - trim_values: true, - bool_tf_str: true - }); - const data_store_do: key_val = { - code: data_store_di.ds_code ?? ds_code, - name: data_store_di.ds_name ?? ds_name, - type: data_store_di.ds_type ?? ds_type, - for_type: data_store_di.ds_for_type ?? null, - for_id: data_store_di.ds_for_id ?? null, - enable: data_store_di.ds_enable ?? true, - account_id: data_store_di.ds_use_account_id ? (data_store_di.ds_account_id ?? $slct.account_id) : null + code: draft_code, + name: draft_name, + type: draft_type, + for_type: for_type, + for_id: for_id, + enable: true, + account_id: draft_use_account_id ? ($ae_loc.account_id || $slct.account_id) : null }; if (data_store_do.type === 'json') { @@ -260,6 +302,12 @@ async function handle_delete() { show_edit = false; } } + +function handle_cancel() { + if (has_changes && !confirm('Discard unsaved changes?')) return; + show_edit = false; + // reset_drafts() will be called by the $effect watching show_edit +}