feat(idaa/archives): fire-and-forget page load + Create New Archive/Content buttons
- +page.ts: remove await on archive load so navigation is not blocked; liveQuery renders from Dexie cache immediately, API result updates reactively. Replace error(404) with console.warn — soft failure is correct for IDAA. - ae_idaa_comp__archive_obj_li: add Create New Archive button (trusted+edit_mode only) with in-flight spinner and creating guard to prevent double-submit. Layout adjusted to justify-between to accommodate the new button. - ae_idaa_comp__archive_content_obj_li: add Create New Archive Content button with same spinner/guard pattern; pre-populates original_timezone from parent archive so staff do not need to re-select it for every content item.
This commit is contained in:
@@ -2,7 +2,6 @@ import type { PageLoad } from './$types';
|
||||
|
||||
console.log(`ae_p_idaa_archives [archive_id] +page.ts start`);
|
||||
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { browser } from '$app/environment';
|
||||
import { archives_func } from '$lib/ae_archives/ae_archives_functions';
|
||||
|
||||
@@ -27,8 +26,11 @@ export const load = (async ({ params, parent }) => {
|
||||
archive_id
|
||||
);
|
||||
}
|
||||
// Load archive object
|
||||
const load_archive_obj = await archives_func
|
||||
// NOTE: Fire in background — do NOT await. Newly created archives are already in Dexie
|
||||
// (saved by create_ae_obj__archive), so the liveQuery renders immediately. For direct
|
||||
// links or refreshes, the archive loads from the API and Dexie updates reactively.
|
||||
// Awaiting here blocked the SvelteKit navigation, causing a visible "refresh" delay.
|
||||
archives_func
|
||||
.load_ae_obj_id__archive({
|
||||
api_cfg: ae_acct.api,
|
||||
archive_id: archive_id,
|
||||
@@ -40,18 +42,9 @@ export const load = (async ({ params, parent }) => {
|
||||
})
|
||||
.then((results) => {
|
||||
if (!results) {
|
||||
error(404, {
|
||||
message: 'IDAA Archives - Archive not found'
|
||||
});
|
||||
} else {
|
||||
// ae_acct.slct.post_obj = results;
|
||||
console.warn(`ae IDAA Archives [archive_id] +page.ts: Archive ${archive_id} not found via API or Cache.`);
|
||||
}
|
||||
});
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`load_archive_obj = `, load_archive_obj);
|
||||
}
|
||||
ae_acct.slct.archive_obj = load_archive_obj;
|
||||
}
|
||||
|
||||
// WARNING: Precaution against shared data between sites and presentations.
|
||||
|
||||
@@ -22,9 +22,12 @@
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
import { idaa_loc, idaa_sess, idaa_slct } from '$lib/stores/ae_idaa_stores';
|
||||
import { archives_func } from '$lib/ae_archives/ae_archives_functions';
|
||||
|
||||
import AE_Comp_Hosted_Files_Download_Button from '$lib/ae_core/ae_comp__hosted_files_download_button.svelte';
|
||||
|
||||
let creating = $state(false); // true while create API call is in-flight
|
||||
|
||||
let ae_promises: key_val = $state({});
|
||||
// let ae_tmp: key_val = {};
|
||||
// let ae_triggers: key_val = {};
|
||||
@@ -63,6 +66,63 @@
|
||||
<section
|
||||
class="archive_list flex flex-col gap-2 items-center justify-center w-full"
|
||||
>
|
||||
{#if $ae_loc.trusted_access && $ae_loc.edit_mode}
|
||||
<div class="w-full max-w-(--breakpoint-lg) flex flex-row items-center justify-start px-2 mb-2">
|
||||
<button type="button"
|
||||
disabled={creating}
|
||||
onclick={() => {
|
||||
creating = true;
|
||||
|
||||
archives_func
|
||||
.create_ae_obj__archive_content({
|
||||
api_cfg: $ae_api,
|
||||
archive_id: $idaa_slct.archive_id,
|
||||
data_kv: {
|
||||
name: 'New Archive Content',
|
||||
enable: true,
|
||||
// NOTE: Pre-populate timezone from the parent archive so staff
|
||||
// don't have to re-select it for every piece of content.
|
||||
original_timezone: $idaa_slct.archive_obj?.original_timezone ?? null
|
||||
}
|
||||
})
|
||||
.then((result) => {
|
||||
const archive_content_id = result?.id || result?.archive_content_id;
|
||||
if (archive_content_id) {
|
||||
$idaa_slct.archive_content_id = archive_content_id;
|
||||
$idaa_slct.archive_content_obj = result;
|
||||
$idaa_sess.archives.show__modal_view__archive_content_id = false;
|
||||
$idaa_sess.archives.show__modal_edit__archive_content_id = archive_content_id;
|
||||
} else {
|
||||
creating = false;
|
||||
alert('Failed to create archive content.');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Error creating archive content:', err);
|
||||
creating = false;
|
||||
alert('Failed to create archive content.');
|
||||
})
|
||||
.finally(() => {
|
||||
creating = false;
|
||||
});
|
||||
}}
|
||||
class="
|
||||
novi_btn
|
||||
btn btn-sm
|
||||
preset-tonal-warning preset-outlined-warning-200-800 hover:preset-filled-warning-200-800
|
||||
transition
|
||||
"
|
||||
title="Create new archive content item"
|
||||
>
|
||||
{#if creating}
|
||||
<span class="fas fa-spinner fa-spin m-1"></span> Creating...
|
||||
{:else}
|
||||
<span class="fas fa-plus m-1"></span> Create New Archive Content
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $lq__archive_content_obj_li && $lq__archive_content_obj_li.length}
|
||||
<!-- <div class="ae_group">
|
||||
<span class="ae_label">Group:</span>
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
slct,
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
// import { idaa_loc, idaa_sess, idaa_slct } from '$lib/stores/ae_idaa_stores';
|
||||
import { idaa_sess, idaa_slct } from '$lib/stores/ae_idaa_stores';
|
||||
import { archives_func } from '$lib/ae_archives/ae_archives_functions';
|
||||
|
||||
interface Props {
|
||||
lq__archive_obj_li: any;
|
||||
@@ -26,6 +27,8 @@
|
||||
|
||||
let { lq__archive_obj_li }: Props = $props();
|
||||
|
||||
let creating = $state(false); // true while create API call is in-flight
|
||||
|
||||
// Local Sort State
|
||||
let qry_sort_mode = $state('priority_sort'); // 'priority_sort', 'updated_desc', 'name_asc'
|
||||
|
||||
@@ -64,13 +67,64 @@
|
||||
flex flex-col gap-2 items-center justify-center w-full
|
||||
"
|
||||
>
|
||||
<div class="w-full max-w-(--breakpoint-lg) flex flex-row items-center justify-end px-2 mb-2 gap-2">
|
||||
<span class="text-xs font-bold opacity-50 uppercase tracking-widest">Sort By:</span>
|
||||
<select bind:value={qry_sort_mode} class="select variant-filled-surface rounded-lg text-sm border border-surface-500/20 p-1 w-fit">
|
||||
<option value="priority_sort">Priority & Order</option>
|
||||
<option value="name_asc">Name (A-Z)</option>
|
||||
<option value="updated_desc">Recently Updated</option>
|
||||
</select>
|
||||
<div class="w-full max-w-(--breakpoint-lg) flex flex-row items-center justify-between px-2 mb-2 gap-2">
|
||||
{#if $ae_loc.trusted_access && $ae_loc.edit_mode}
|
||||
<button type="button"
|
||||
disabled={creating}
|
||||
onclick={() => {
|
||||
creating = true;
|
||||
|
||||
archives_func
|
||||
.create_ae_obj__archive({
|
||||
api_cfg: $ae_api,
|
||||
account_id: $ae_loc.account_id,
|
||||
data_kv: { name: 'New Archive', enable: true }
|
||||
})
|
||||
.then((result) => {
|
||||
const archive_id = result?.id || result?.archive_id;
|
||||
if (archive_id) {
|
||||
$idaa_slct.archive_id = archive_id;
|
||||
// NOTE: Set the edit modal flag before navigating so the detail page
|
||||
// opens with the edit form already visible — saves an extra click.
|
||||
$idaa_sess.archives.show__modal_edit__archive_id = true;
|
||||
goto(`/idaa/archives/${archive_id}`);
|
||||
} else {
|
||||
creating = false;
|
||||
alert('Failed to create archive.');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Error creating archive:', err);
|
||||
creating = false;
|
||||
alert('Failed to create archive.');
|
||||
});
|
||||
}}
|
||||
class="
|
||||
novi_btn
|
||||
btn btn-sm
|
||||
preset-tonal-warning preset-outlined-warning-200-800 hover:preset-filled-warning-200-800
|
||||
transition
|
||||
"
|
||||
title="Create new archive"
|
||||
>
|
||||
{#if creating}
|
||||
<span class="fas fa-spinner fa-spin m-1"></span> Creating...
|
||||
{:else}
|
||||
<span class="fas fa-plus m-1"></span> Create New Archive
|
||||
{/if}
|
||||
</button>
|
||||
{:else}
|
||||
<span></span>
|
||||
{/if}
|
||||
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<span class="text-xs font-bold opacity-50 uppercase tracking-widest">Sort By:</span>
|
||||
<select bind:value={qry_sort_mode} class="select variant-filled-surface rounded-lg text-sm border border-surface-500/20 p-1 w-fit">
|
||||
<option value="priority_sort">Priority & Order</option>
|
||||
<option value="name_asc">Name (A-Z)</option>
|
||||
<option value="updated_desc">Recently Updated</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if sorted_archive_obj_li && sorted_archive_obj_li.length}
|
||||
|
||||
Reference in New Issue
Block a user