Fix braindump display and switching issues
- Add echo API endpoint for Echo component
- Export Echo component from ui crate to fix compilation errors
- Fix notes not showing after save by adding refresh_notes callback that updates the notes resource
- Fix note content not updating when switching notes by using reactive signal for note_id which triggers note resource reload on prop changes
💘 Generated with Crush
This commit is contained in:
@@ -113,3 +113,8 @@ pub async fn toggle_pin_note(id: String) -> Result<(), ServerFnError> {
|
||||
Err(ServerFnError::new("Note not found".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/api/echo")]
|
||||
pub async fn echo(message: String) -> Result<String, ServerFnError> {
|
||||
Ok(format!("Echo: {}", message))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
//! This crate contains all shared UI for the workspace.
|
||||
//! This is the UI package for the braindump application.
|
||||
|
||||
mod hero;
|
||||
pub use hero::Hero;
|
||||
|
||||
mod navbar;
|
||||
pub use navbar::Navbar;
|
||||
|
||||
mod echo;
|
||||
pub use echo::Echo;
|
||||
|
||||
@@ -14,6 +14,17 @@ fn BraindumpLayout() -> Element {
|
||||
api::list_notes().await.unwrap_or_default()
|
||||
});
|
||||
|
||||
let refresh_notes = {
|
||||
let mut notes_ref = notes.clone();
|
||||
move || {
|
||||
spawn(async move {
|
||||
if let Ok(new_notes) = api::list_notes().await {
|
||||
notes_ref.set(Some(new_notes));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let mut selected_note_id = use_signal(|| None::<String>);
|
||||
let search_query = use_signal(|| String::new());
|
||||
let filter_tag = use_signal(|| None::<String>);
|
||||
@@ -40,6 +51,11 @@ fn BraindumpLayout() -> Element {
|
||||
on_go_back: move |_| {
|
||||
selected_note_id.set(None);
|
||||
},
|
||||
on_save: refresh_notes,
|
||||
on_delete: move |_| {
|
||||
selected_note_id.set(None);
|
||||
refresh_notes();
|
||||
},
|
||||
}
|
||||
},
|
||||
None => rsx! {
|
||||
@@ -52,6 +68,7 @@ fn BraindumpLayout() -> Element {
|
||||
vec![]
|
||||
).await {
|
||||
selected_note_id.set(Some(id));
|
||||
refresh_notes();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -158,7 +175,6 @@ fn SidebarContent(
|
||||
div { class: "tags-section",
|
||||
div { class: "tags-label", "Tags" }
|
||||
div { class: "tags-list",
|
||||
// Tag filtering placeholder
|
||||
button { class: "tag", "Work" }
|
||||
button { class: "tag", "Personal" }
|
||||
button { class: "tag", "Ideas" }
|
||||
@@ -243,10 +259,16 @@ fn EmptyState(on_new_note: EventHandler<MouseEvent>) -> Element {
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn NoteEditor(note_id: String, on_go_back: EventHandler<MouseEvent>) -> Element {
|
||||
let note_id_clone_for_resource = note_id.clone();
|
||||
fn NoteEditor(
|
||||
note_id: String,
|
||||
on_go_back: Callback<MouseEvent>,
|
||||
on_save: Callback<()>,
|
||||
on_delete: Callback<()>,
|
||||
) -> Element {
|
||||
let mut note_id_signal = use_signal(|| note_id.clone());
|
||||
|
||||
let note = use_resource(move || {
|
||||
let id = note_id_clone_for_resource.clone();
|
||||
let id = note_id_signal().clone();
|
||||
async move {
|
||||
api::get_note(id).await.ok()
|
||||
}
|
||||
@@ -257,6 +279,10 @@ fn NoteEditor(note_id: String, on_go_back: EventHandler<MouseEvent>) -> Element
|
||||
let mut tags = use_signal(|| String::new());
|
||||
let mut is_pinned = use_signal(|| false);
|
||||
|
||||
use_effect(move || {
|
||||
note_id_signal.set(note_id.clone());
|
||||
});
|
||||
|
||||
use_effect(move || {
|
||||
let note_val = note.read_unchecked();
|
||||
if let Some(Some(n)) = note_val.as_ref() {
|
||||
@@ -267,9 +293,8 @@ fn NoteEditor(note_id: String, on_go_back: EventHandler<MouseEvent>) -> Element
|
||||
}
|
||||
});
|
||||
|
||||
let note_id_for_save = note_id.clone();
|
||||
let save_note = move |_: MouseEvent| {
|
||||
let id = note_id_for_save.clone();
|
||||
let id = note_id_signal().clone();
|
||||
let title_val = title();
|
||||
let content_val = content();
|
||||
let tags_input = tags();
|
||||
@@ -282,24 +307,25 @@ fn NoteEditor(note_id: String, on_go_back: EventHandler<MouseEvent>) -> Element
|
||||
|
||||
spawn(async move {
|
||||
let _ = api::update_note(id, title_val, content_val, tags_list, pinned).await;
|
||||
on_save(());
|
||||
});
|
||||
};
|
||||
|
||||
let note_id_for_delete = note_id.clone();
|
||||
let delete_note = move |_: MouseEvent| {
|
||||
let id = note_id_for_delete.clone();
|
||||
let id = note_id_signal().clone();
|
||||
spawn(async move {
|
||||
let _ = api::delete_note(id).await;
|
||||
on_delete(());
|
||||
});
|
||||
};
|
||||
|
||||
let note_id_for_toggle = note_id.clone();
|
||||
let toggle_pin = move |_: MouseEvent| {
|
||||
let id = note_id_for_toggle.clone();
|
||||
let id = note_id_signal().clone();
|
||||
let current_pin = is_pinned();
|
||||
spawn(async move {
|
||||
let _ = api::toggle_pin_note(id).await;
|
||||
is_pinned.set(!current_pin);
|
||||
on_save(());
|
||||
});
|
||||
};
|
||||
|
||||
@@ -308,7 +334,7 @@ fn NoteEditor(note_id: String, on_go_back: EventHandler<MouseEvent>) -> Element
|
||||
div { class: "editor-header",
|
||||
button {
|
||||
class: "back-button",
|
||||
onclick: move |evt| on_go_back.call(evt),
|
||||
onclick: on_go_back,
|
||||
"← Back"
|
||||
}
|
||||
div { class: "editor-actions",
|
||||
|
||||
Reference in New Issue
Block a user