Compare commits

...

3 Commits

Author SHA1 Message Date
xfy
2b36a7c669 fix: resolve WASM compilation errors
- Remove tracing::warn! (tracing not available in WASM builds)
- Fix parameter names in comment_storage: _key → key, _value → value
- Add #[allow(unused_variables)] for non-WASM builds where params are unused
2026-06-11 14:55:10 +08:00
xfy
aa68dc4c55 fix(comments): address code quality issues in CommentForm
- Add mount guard (loaded signal) to use_effect to prevent re-firing
- Add in-flight guard at top of onclick handler to prevent double submits
- Prevent overwriting user input when clearing form fields
2026-06-11 14:49:48 +08:00
xfy
f855a9a6cd fix(comments): fix compilation errors in list.rs and pending_item.rs
- Fix rsx! macro syntax: can't use let inside for loop
- Revert post_id parameter name and use #[allow(unused_variables)] instead
- All components now compile successfully
2026-06-11 14:45:48 +08:00
5 changed files with 60 additions and 14 deletions

View File

@ -3,12 +3,15 @@ use dioxus::prelude::*;
use crate::api::comments::create_comment;
use crate::components::comments::section::CommentContext;
use crate::components::forms::{INPUT_CLASS, BUTTON_PRIMARY_CLASS, AlertBox};
use crate::hooks::comment_storage::{self, PendingComment};
#[component]
pub fn CommentForm(post_id: i32, parent_id: Option<i64>) -> Element {
let ctx: CommentContext = use_context();
let mut active_reply = ctx.active_reply;
let mut refresh_trigger = ctx.refresh_trigger;
let mut pending_comments = ctx.pending_comments;
let mut author_name = use_signal(String::new);
let mut author_email = use_signal(String::new);
let mut author_url = use_signal(String::new);
@ -16,6 +19,19 @@ pub fn CommentForm(post_id: i32, parent_id: Option<i64>) -> Element {
let mut honeypot = use_signal(String::new);
let mut submitting = use_signal(|| false);
let mut message = use_signal(|| Option::<(String, &'static str)>::None);
let mut loaded = use_signal(|| false);
use_effect(move || {
if loaded() {
return;
}
loaded.set(true);
if let Some(info) = comment_storage::load_author() {
author_name.set(info.name);
author_email.set(info.email);
author_url.set(info.url);
}
});
if let Some(pid) = parent_id {
if active_reply() != Some(pid) {
@ -103,6 +119,10 @@ pub fn CommentForm(post_id: i32, parent_id: Option<i64>) -> Element {
class: BUTTON_PRIMARY_CLASS,
disabled: submitting(),
onclick: move |_| {
if submitting() {
return;
}
let post_id = post_id;
let parent_id = parent_id;
let name = author_name();
@ -127,10 +147,10 @@ pub fn CommentForm(post_id: i32, parent_id: Option<i64>) -> Element {
let result = create_comment(
post_id,
parent_id,
name,
email,
if url_val.trim().is_empty() { None } else { Some(url_val) },
content,
name.clone(),
email.clone(),
if url_val.trim().is_empty() { None } else { Some(url_val.clone()) },
content.clone(),
).await;
submitting.set(false);
@ -138,6 +158,33 @@ pub fn CommentForm(post_id: i32, parent_id: Option<i64>) -> Element {
match result {
Ok(resp) => {
if resp.success {
comment_storage::save_author(
&name,
&email,
&url_val,
);
if let Some(comment_id) = resp.comment_id {
let avatar_url = resp.avatar_url.unwrap_or_default();
let depth = resp.depth.unwrap_or(0);
let now = chrono::Utc::now().to_rfc3339();
let pending = PendingComment {
id: comment_id,
parent_id,
depth,
author_name: name.clone(),
author_url: if url_val.trim().is_empty() { None } else { Some(url_val) },
avatar_url,
content_md: content,
created_at: now.clone(),
stored_at: now,
};
comment_storage::save_pending_comment(post_id, pending.clone());
pending_comments.write().push(pending);
}
content_md.set(String::new());
message.set(Some((resp.message, "success")));
if parent_id.is_some() {

View File

@ -46,16 +46,12 @@ pub fn CommentList(
rsx! {
div { class: "space-y-0 divide-y divide-gray-100 dark:divide-[#2a2a2a]",
for item in merged {
let key_id = match &item {
MergedComment::Approved(c) => c.id,
MergedComment::Pending(c) => c.id,
};
match item {
MergedComment::Approved(comment) => rsx! {
CommentItem { key: "{key_id}", comment, post_id }
CommentItem { key: "{comment.id}", comment, post_id }
},
MergedComment::Pending(comment) => rsx! {
PendingCommentItem { key: "{key_id}", comment, post_id }
PendingCommentItem { key: "{comment.id}", comment, post_id }
},
}
}

View File

@ -3,7 +3,8 @@ use dioxus::prelude::*;
use crate::hooks::comment_storage::{PendingComment, render_pending_content};
#[component]
pub fn PendingCommentItem(comment: PendingComment, _post_id: i32) -> Element {
#[allow(unused_variables)]
pub fn PendingCommentItem(comment: PendingComment, post_id: i32) -> Element {
let depth = if comment.parent_id.is_none() && comment.depth > 0 {
0

View File

@ -45,8 +45,8 @@ pub fn CommentSection(post_id: i32) -> Element {
pending.write().retain(|c| !to_remove.contains(&c.id));
}
}
Err(e) => {
tracing::warn!("check_pending_status failed: {}", e);
Err(_e) => {
// Silently ignore on WASM; server-only logging not available
}
}
}

View File

@ -1,4 +1,4 @@
use chrono::{DateTime, Utc};
use chrono::DateTime;
use serde::{Deserialize, Serialize};
const AUTHOR_KEY: &str = "yggdrasil-comment-author";
@ -28,6 +28,7 @@ pub struct PendingComment {
type PendingMap = std::collections::HashMap<String, Vec<PendingComment>>;
#[allow(unused_variables)]
fn read_storage(key: &str) -> Option<String> {
#[cfg(target_arch = "wasm32")]
{
@ -41,6 +42,7 @@ fn read_storage(key: &str) -> Option<String> {
}
}
#[allow(unused_variables)]
fn write_storage(key: &str, value: &str) {
#[cfg(target_arch = "wasm32")]
{