feat(idaa): stabilize Bulletin Board module and resolve creation crashes
- Fixed 'post_id' missing error in comment creation by mapping to 'post_id_random'. - Resolved infinite request loop in post view via untrack() optimization. - Hardened all property accesses with optional chaining to prevent TypeErrors. - Migrated comment editor to local reactive state for Svelte 5 stability. - Refactored post visibility layer to use derived reactive filtering. - Standardized ID mapping patterns across all BB components.
This commit is contained in:
@@ -120,7 +120,7 @@ export interface Post_Comment {
|
||||
export class MySubClassedDexie extends Dexie {
|
||||
// We just tell the typing system this is the case
|
||||
post!: Table<Post>;
|
||||
post_comment!: Table<Post_Comment>;
|
||||
comment!: Table<Post_Comment>;
|
||||
|
||||
constructor() {
|
||||
super('ae_posts_db');
|
||||
@@ -136,7 +136,7 @@ export class MySubClassedDexie extends Dexie {
|
||||
tmp_sort_1, tmp_sort_2,
|
||||
enable, hide, priority, sort, group, notes, created_on, updated_on, [updated_on+created_on], [created_on+updated_on]`,
|
||||
|
||||
post_comment: `
|
||||
comment: `
|
||||
id, post_comment_id,
|
||||
post_id,
|
||||
name,
|
||||
|
||||
@@ -91,66 +91,37 @@
|
||||
// Form Post object data outgoing
|
||||
let post_comment_do: key_val = {};
|
||||
|
||||
// SVELTE 5: Map values from local form state to payload
|
||||
post_comment_do['content'] = content_new_html;
|
||||
post_comment_do['anonymous'] = post_comment_form.anonymous;
|
||||
post_comment_do['external_person_id'] = post_comment_form.external_person_id;
|
||||
post_comment_do['full_name'] = post_comment_form.full_name;
|
||||
post_comment_do['email'] = post_comment_form.email;
|
||||
post_comment_do['notify'] = post_comment_di.notify ?? true; // Default to true if not found
|
||||
|
||||
post_comment_do['hide'] = post_comment_form.hide;
|
||||
post_comment_do['priority'] = post_comment_form.priority;
|
||||
post_comment_do['sort'] = post_comment_form.sort ? Number(post_comment_form.sort) : null;
|
||||
post_comment_do['group'] = post_comment_form.group ?? null;
|
||||
post_comment_do['enable'] = post_comment_form.enable ?? true;
|
||||
|
||||
if (!$idaa_slct.post_comment_id) {
|
||||
// NEW COMMENT: Ensure post_id is included
|
||||
const parent_post_id = $idaa_slct.post_id;
|
||||
post_comment_do['post_id'] = parent_post_id;
|
||||
post_comment_do['post_id_random'] = parent_post_id;
|
||||
post_comment_do['enable'] = true;
|
||||
// post_comment_do['post_id_random'] = parent_post_id;
|
||||
}
|
||||
|
||||
// post_comment_do['title'] = post_comment_di.title;
|
||||
|
||||
// Check if the content_new_html exists and is a string
|
||||
if (typeof content_new_html === 'string') {
|
||||
console.log('New content is a string');
|
||||
post_comment_do['content'] = content_new_html;
|
||||
} else {
|
||||
console.log('New content is not a string. Do nothing.');
|
||||
// post_comment_do['content'] = event_meeting_fd.content;
|
||||
}
|
||||
|
||||
post_comment_do['anonymous'] = post_comment_di.anonymous;
|
||||
|
||||
post_comment_do['external_person_id'] = post_comment_di.external_person_id;
|
||||
post_comment_do['full_name'] = post_comment_di.full_name;
|
||||
post_comment_do['email'] = post_comment_di.email;
|
||||
post_comment_do['notify'] = post_comment_di.notify;
|
||||
|
||||
post_comment_do['hide'] = post_comment_di.hide;
|
||||
post_comment_do['priority'] = post_comment_di.priority;
|
||||
if (post_comment_di.sort) {
|
||||
post_comment_do['sort'] = Number(post_comment_di.sort);
|
||||
} else {
|
||||
post_comment_do['sort'] = null;
|
||||
}
|
||||
if (post_comment_di.group) {
|
||||
post_comment_do['group'] = post_comment_di.group;
|
||||
} else {
|
||||
post_comment_do['group'] = null;
|
||||
}
|
||||
|
||||
// NOTE: We only want to set enable value if the input is defined.
|
||||
if (typeof post_comment_di.enable !== 'undefined') {
|
||||
post_comment_do.enable = post_comment_di.enable;
|
||||
}
|
||||
// NOTE: We want to always default to false if the input is not defined.
|
||||
// post_comment_do.enable = post_comment_di.enable ?? false;
|
||||
|
||||
// // Check if the notes_new_html exists and is a string
|
||||
// if (typeof $idaa_slct.post_comment_obj.notes_new_html === 'string') {
|
||||
// console.log('New notes is a string');
|
||||
// post_comment_do['notes'] = $idaa_slct.post_comment_obj.notes_new_html;
|
||||
// } else {
|
||||
// console.log('New notes is not a string. Do nothing.');
|
||||
// // post_comment_do['notes'] = event_meeting_fd.notes;
|
||||
// }
|
||||
|
||||
log_lvl = 1;
|
||||
if (log_lvl) {
|
||||
console.log(post_comment_do);
|
||||
console.log('Final Payload (post_comment_do):', post_comment_do);
|
||||
}
|
||||
|
||||
if (!$idaa_slct.post_comment_id) {
|
||||
// NEW COMMENT: Ensure post_id_random is included
|
||||
// SVELTE 5 V3 Pattern: Some child objects require the random ID suffix for parent mapping
|
||||
post_comment_do['post_id_random'] = $idaa_slct.post_id;
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`Current Post Comment Object List Length: ${$idaa_slct.post_comment_obj_li.length}`,
|
||||
@@ -166,70 +137,51 @@
|
||||
data_kv: post_comment_do,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
// .then(function (post_comment_obj_create_result) {
|
||||
// if (!post_comment_obj_create_result) {
|
||||
// console.log('The result was null or false.');
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// $idaa_slct.post_comment_id = post_comment_obj_create_result.post_comment_id_random;
|
||||
// $idaa_slct.post_comment_obj = post_comment_obj_create_result;
|
||||
|
||||
// return post_comment_obj_create_result;
|
||||
// })
|
||||
.catch(function (error: any) {
|
||||
console.log('Something went wrong.');
|
||||
console.log(error);
|
||||
return false;
|
||||
// })
|
||||
// .finally(async () => {
|
||||
});
|
||||
|
||||
$idaa_slct.post_comment_id = prom_api__post_comment_obj.post_comment_id_random;
|
||||
$idaa_slct.post_comment_obj = prom_api__post_comment_obj;
|
||||
if (prom_api__post_comment_obj) {
|
||||
$idaa_slct.post_comment_id = prom_api__post_comment_obj.post_comment_id_random;
|
||||
$idaa_slct.post_comment_obj = prom_api__post_comment_obj;
|
||||
|
||||
disable_submit_btn = false;
|
||||
$idaa_sess.bb.show__inline_edit__post_comment_id = false;
|
||||
disable_submit_btn = false;
|
||||
$idaa_sess.bb.show__inline_edit__post_comment_id = false;
|
||||
|
||||
// Send notification to staff
|
||||
// if (!$ae_loc.administrator_access && $ae_loc.site_cfg_json?.bb_send_staff_new_email) {
|
||||
if ($ae_loc.site_cfg_json?.bb_send_staff_new_email) {
|
||||
send_staff_notification_email();
|
||||
}
|
||||
// Send notification to staff
|
||||
if ($ae_loc.site_cfg_json?.bb_send_staff_new_email) {
|
||||
send_staff_notification_email();
|
||||
}
|
||||
|
||||
// Send notification to the original poster
|
||||
if (
|
||||
!$ae_loc.administrator_access &&
|
||||
$ae_loc.site_cfg_json?.bb_send_poster_email &&
|
||||
$idaa_slct.post_obj.notify
|
||||
) {
|
||||
// if ($ae_loc.site_cfg_json?.bb_send_poster_email && $idaa_slct.post_obj.notify) {
|
||||
send_poster_notification_email();
|
||||
}
|
||||
// Send notification to the original poster
|
||||
if (
|
||||
!$ae_loc.administrator_access &&
|
||||
$ae_loc.site_cfg_json?.bb_send_poster_email &&
|
||||
$idaa_slct.post_obj.notify
|
||||
) {
|
||||
send_poster_notification_email();
|
||||
}
|
||||
|
||||
// Send a notification to any other post commenters
|
||||
if (!$ae_loc.administrator_access && $ae_loc.site_cfg_json?.bb_send_commenter_email) {
|
||||
console.log(
|
||||
`Sending notification email to post commenters...: ${$idaa_slct.post_comment_obj_li?.length}`
|
||||
);
|
||||
if ($idaa_slct.post_comment_obj_li && $idaa_slct.post_comment_obj_li.length > 0) {
|
||||
for (const post_comment of $idaa_slct.post_comment_obj_li) {
|
||||
console.log('Post Comment ID:', post_comment.post_comment_id);
|
||||
if (
|
||||
post_comment?.email &&
|
||||
post_comment.post_comment_id !== $idaa_slct.post_comment_id &&
|
||||
post_comment?.email !== $idaa_slct.post_comment_obj?.email
|
||||
) {
|
||||
console.log(
|
||||
`Sending notification email to post commenter: ${post_comment.full_name}`,
|
||||
post_comment
|
||||
);
|
||||
send_poster_commenters_notification_email({
|
||||
post_comment_obj: post_comment
|
||||
});
|
||||
// Send a notification to any other post commenters
|
||||
if (!$ae_loc.administrator_access && $ae_loc.site_cfg_json?.bb_send_commenter_email) {
|
||||
if ($idaa_slct.post_comment_obj_li && $idaa_slct.post_comment_obj_li.length > 0) {
|
||||
for (const post_comment of $idaa_slct.post_comment_obj_li) {
|
||||
if (
|
||||
post_comment?.email &&
|
||||
post_comment.post_comment_id !== $idaa_slct.post_comment_id &&
|
||||
post_comment?.email !== $idaa_slct.post_comment_obj?.email
|
||||
) {
|
||||
send_poster_commenters_notification_email({
|
||||
post_comment_obj: post_comment
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
disable_submit_btn = false;
|
||||
}
|
||||
|
||||
return prom_api__post_comment_obj;
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
let upload_complete = $state(false);
|
||||
let disable_submit_btn = $state(false);
|
||||
|
||||
function preventDefault<T extends Event>(fn: (event: T) => void) {
|
||||
function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||
return function (event: T) {
|
||||
event.preventDefault();
|
||||
fn(event);
|
||||
@@ -102,7 +102,8 @@
|
||||
let post_do: key_val = {};
|
||||
|
||||
if (!$idaa_slct.post_id) {
|
||||
post_do['account_id_random'] = $ae_loc.account_id;
|
||||
// V3 Standard: Use clean ID field name for isolation
|
||||
post_do['account_id'] = $ae_loc.account_id;
|
||||
post_do['enable'] = true;
|
||||
}
|
||||
|
||||
@@ -365,6 +366,11 @@ Copy and paste link: <a href="${link_base_url}?post_id=${$idaa_slct.post_id}">${
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
// Initialization Layer
|
||||
if (!orig_post_obj?.id && $idaa_slct.post_obj?.id) {
|
||||
orig_post_obj = { ...$idaa_slct.post_obj };
|
||||
}
|
||||
|
||||
if (
|
||||
orig_post_obj === null ||
|
||||
orig_post_obj === undefined ||
|
||||
@@ -379,8 +385,10 @@ Copy and paste link: <a href="${link_base_url}?post_id=${$idaa_slct.post_id}">${
|
||||
notes_new_html !== (orig_post_obj.notes ?? ''))
|
||||
) {
|
||||
// console.log('Post object has changed from original.', $inspect(orig_post_obj));
|
||||
console.log('Post object has changed from original.', orig_post_obj);
|
||||
console.log('Post object has changed.', $idaa_slct.post_obj);
|
||||
if (log_lvl) {
|
||||
console.log('Post object has changed from original.', orig_post_obj);
|
||||
console.log('Post object has changed.', $idaa_slct.post_obj);
|
||||
}
|
||||
obj_changed = true;
|
||||
} else if (
|
||||
obj_changed &&
|
||||
@@ -411,7 +419,7 @@ Copy and paste link: <a href="${link_base_url}?post_id=${$idaa_slct.post_id}">${
|
||||
class:ae_create={!$idaa_slct.post_id}
|
||||
bind:clientHeight={$ae_loc.iframe_height_modal_body}
|
||||
>
|
||||
<form onsubmit={preventDefault(handle_submit_form)} class="space-y-1">
|
||||
<form onsubmit={prevent_default(handle_submit_form)} class="space-y-1">
|
||||
{#await prom_api__post_obj}
|
||||
<div class="awaiting alert_msg_pulse" out:fade={{ duration: 2000 }}>Saving...</div>
|
||||
{:then}
|
||||
|
||||
@@ -26,6 +26,40 @@
|
||||
|
||||
let { data, lq__post_obj_li }: Props = $props();
|
||||
|
||||
// Derived list of visible items (Refactored 2026-02-05)
|
||||
let visible_post_obj_li = $derived.by(() => {
|
||||
const list = $lq__post_obj_li;
|
||||
if (!list || !Array.isArray(list)) return [];
|
||||
|
||||
const filtered = list.filter((post: any) => {
|
||||
if (!post) return false;
|
||||
|
||||
/**
|
||||
* DUAL-LAYER VISIBILITY LOGIC
|
||||
* 1. Public Logic: If an item is enabled and NOT hidden, everyone sees it.
|
||||
* 2. Trusted Logic: If an item is disabled OR hidden, ONLY trusted users see it.
|
||||
*
|
||||
* NOTE: We also respect the active query filters for hidden/enabled.
|
||||
*/
|
||||
const is_hidden = post.hide == true;
|
||||
const is_disabled = post.enable == false;
|
||||
|
||||
// Strict Filter Mapping (from UI dropdowns)
|
||||
if ($idaa_loc.bb.qry__hidden === 'hidden' && !is_hidden) return false;
|
||||
if ($idaa_loc.bb.qry__hidden === 'not_hidden' && is_hidden) return false;
|
||||
if ($idaa_loc.bb.qry__enabled === 'enabled' && is_disabled) return false;
|
||||
if ($idaa_loc.bb.qry__enabled === 'not_enabled' && !is_disabled) return false;
|
||||
|
||||
if (!is_hidden && !is_disabled) return true;
|
||||
|
||||
return ($ae_loc.trusted_access === true);
|
||||
});
|
||||
|
||||
if (log_lvl) console.log(`visible_post_obj_li: Input=${list.length}, Output=${filtered.length} (trusted=${$ae_loc.trusted_access})`);
|
||||
|
||||
return filtered;
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
@@ -37,16 +71,14 @@
|
||||
</script>
|
||||
|
||||
<section class="bb_post_list flex flex-col gap-2 items-center justify-center w-full">
|
||||
{#if $lq__post_obj_li && $lq__post_obj_li.length}
|
||||
{#each $lq__post_obj_li as idaa_post_obj, index}
|
||||
{#if visible_post_obj_li && visible_post_obj_li.length}
|
||||
{#each visible_post_obj_li as idaa_post_obj, index}
|
||||
{#if idaa_post_obj}
|
||||
<!-- This check for the idaa_post_obj is here in case the IDB entry is deleted. -->
|
||||
<div
|
||||
class="container bb_post post_obj border p-2 mb-2 space-y-2 w-full max-w-(--breakpoint-lg) flex flex-col items-center justify-center bg-white rounded-lg"
|
||||
class:dim={idaa_post_obj?.hide}
|
||||
class:bg-warning-100={!idaa_post_obj?.enable}
|
||||
class:hidden={(idaa_post_obj.hide && $idaa_loc.bb.qry__hidden != 'all') ||
|
||||
(!idaa_post_obj.enable && $idaa_loc.bb.qry__enabled != 'all')}
|
||||
>
|
||||
<header class="ae_header">
|
||||
<h3
|
||||
|
||||
@@ -200,27 +200,24 @@
|
||||
if (log_lvl) {
|
||||
console.log('New post created:', results);
|
||||
}
|
||||
$idaa_slct.post_id = results?.post_id_random;
|
||||
// V3 Standard: Use clean ID field names
|
||||
const clean_post_id = results?.id || results?.post_id;
|
||||
$idaa_slct.post_id = clean_post_id;
|
||||
$idaa_slct.post_obj = {
|
||||
...results
|
||||
};
|
||||
$idaa_sess.bb.edit__post_obj = $idaa_slct.post_id;
|
||||
$idaa_loc.bb.edit__post_obj = $idaa_slct.post_id;
|
||||
|
||||
// if (!$idaa_loc.bb.edit_kv) {
|
||||
// $idaa_loc.bb.edit_kv = {};
|
||||
// }
|
||||
// $idaa_loc.bb.edit_kv[$idaa_slct.post_id] = 'current';
|
||||
|
||||
// alert(`Post created successfully! ${$idaa_slct.post_id}`);
|
||||
$idaa_sess.bb.edit__post_obj = clean_post_id;
|
||||
$idaa_loc.bb.edit__post_obj = clean_post_id;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error updating post:', error);
|
||||
alert('Failed to update post.');
|
||||
console.error('Error creating post:', error);
|
||||
alert('Failed to create post.');
|
||||
})
|
||||
.finally(() => {
|
||||
if ($idaa_slct.post_id) {
|
||||
goto(`/idaa/bb/${$idaa_slct.post_id}`);
|
||||
const final_id = $idaa_slct.post_id;
|
||||
if (final_id) {
|
||||
if (log_lvl) console.log(`Redirecting to new post: ${final_id}`);
|
||||
goto(`/idaa/bb/${final_id}`);
|
||||
} else {
|
||||
alert('Failed to create new post.');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user