feat(item_list): update save_item_to_db function to take current_url as an argument.

Changes:

* Replaced `let current_url = get_current_url();` with `let current_url = Rc::new(get_current_url());` to share the current URL between closures.
* Wrapped `add_property` and `update_item` functions in Arc to share them between closures.
* Updated `save_item_to_db` function to take `current_url` as an argument and use it to construct the ItemToSend struct.
* Updated `fetch_property_labels` function to use the `property_ids` vector instead of a single property ID.
* Updated `fetch_item_properties` function to use the `wikidata_id` parameter instead of a hardcoded value.
* Updated `WikidataResponse` struct to use a `Vec<WikidataSuggestion>` instead of a single `WikidataSuggestion`.
This commit is contained in:
ryan 2025-02-18 20:01:45 +03:00
parent 63f11f6a2d
commit 9beb997125

View file

@ -9,7 +9,7 @@ use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
use web_sys::window; use web_sys::window;
use std::rc::Rc;
#[derive(Deserialize, Clone, Debug)] #[derive(Deserialize, Clone, Debug)]
struct WikidataSuggestion { struct WikidataSuggestion {
id: String, id: String,
@ -29,7 +29,7 @@ struct DbItem {
//function to load items from database //function to load items from database
pub async fn load_items_from_db(current_url: &str) -> Result<Vec<Item>, String> { pub async fn load_items_from_db(current_url: &str) -> Result<Vec<Item>, String> {
let response = gloo_net::http::Request::get("/api/items?url={}") let response = gloo_net::http::Request::get(&format!("/api/items?url={}", current_url))
.send() .send()
.await .await
.map_err(|err| format!("Failed to fetch items: {:?}", err))?; .map_err(|err| format!("Failed to fetch items: {:?}", err))?;
@ -101,9 +101,11 @@ pub fn ItemsList(
.unwrap_or_else(|| "".to_string()) .unwrap_or_else(|| "".to_string())
} }
let current_url = get_current_url(); let current_url = Rc::new(get_current_url());
spawn_local(async move { spawn_local({
let current_url = Rc::clone(&current_url);
async move {
match load_items_from_db(&current_url).await { match load_items_from_db(&current_url).await {
Ok(loaded_items) => { Ok(loaded_items) => {
// Set the loaded items // Set the loaded items
@ -158,7 +160,7 @@ pub fn ItemsList(
log!("Error loading items: {}", err); log!("Error loading items: {}", err);
} }
} }
}); }});
// Ensure there's an initial empty row // Ensure there's an initial empty row
@ -173,7 +175,7 @@ pub fn ItemsList(
} }
// Function to send an item to the backend API // Function to send an item to the backend API
async fn save_item_to_db(item: Item, selected_properties: ReadSignal<HashMap<String, bool>>) { async fn save_item_to_db(item: Item, selected_properties: ReadSignal<HashMap<String, bool>>, current_url: String) {
// Use a reactive closure to access `selected_properties` // Use a reactive closure to access `selected_properties`
let custom_properties: HashMap<String, String> = (move || { let custom_properties: HashMap<String, String> = (move || {
let selected_props = selected_properties.get(); // Access the signal inside a reactive closure let selected_props = selected_properties.get(); // Access the signal inside a reactive closure
@ -189,6 +191,7 @@ pub fn ItemsList(
// Create a new struct to send to the backend // Create a new struct to send to the backend
#[derive(Serialize, Debug)] #[derive(Serialize, Debug)]
struct ItemToSend { struct ItemToSend {
url: String,
id: String, id: String,
name: String, name: String,
description: String, description: String,
@ -197,6 +200,7 @@ pub fn ItemsList(
} }
let item_to_send = ItemToSend { let item_to_send = ItemToSend {
url: current_url.to_string(),
id: item.id, id: item.id,
name: item.name, name: item.name,
description: item.description, description: item.description,
@ -439,7 +443,10 @@ pub fn ItemsList(
} }
// Add a new custom property // Add a new custom property
let add_property = move |property: String| { let add_property = {
let current_url = Rc::clone(&current_url);
let set_items = set_items.clone();
Arc::new(move |property: String| {
// Normalize the property ID // Normalize the property ID
let normalized_property = property.replace("http://www.wikidata.org/prop/", ""); let normalized_property = property.replace("http://www.wikidata.org/prop/", "");
@ -459,8 +466,11 @@ pub fn ItemsList(
// Save the updated item to the database // Save the updated item to the database
let item_clone = item.clone(); let item_clone = item.clone();
spawn_local(async move { spawn_local({
save_item_to_db(item_clone, selected_properties).await; let current_url = Rc::clone(&current_url);
async move {
save_item_to_db(item_clone, selected_properties, current_url.to_string()).await;
}
}); });
} }
}); });
@ -509,11 +519,16 @@ pub fn ItemsList(
} }
} }
}); });
}; })};
// Update item fields // Update item fields
let update_item = move |index: usize, field: &str, value: String| { let update_item = {
set_items.update(|items| { let set_items = set_items.clone();
let current_url = Rc::clone(&current_url);
Arc::new(move |index: usize, field: &str, value: String| {
let set_items = set_items.clone();
let current_url = Rc::clone(&current_url);
set_items.update(move|items| {
if let Some(item) = items.get_mut(index) { if let Some(item) = items.get_mut(index) {
match field { match field {
"name" => { "name" => {
@ -544,8 +559,11 @@ pub fn ItemsList(
// Save the updated item to the database // Save the updated item to the database
let item_clone = item.clone(); let item_clone = item.clone();
spawn_local(async move { spawn_local({
save_item_to_db(item_clone, selected_properties).await; let current_url = Rc::clone(&current_url);
async move {
save_item_to_db(item_clone, selected_properties, current_url.to_string()).await;
}
}); });
} }
// Automatically add a new row when editing the last row // Automatically add a new row when editing the last row
@ -561,13 +579,16 @@ pub fn ItemsList(
items.push(new_item.clone()); items.push(new_item.clone());
// Save the new item to the database // Save the new item to the database
spawn_local(async move { spawn_local({
save_item_to_db(new_item, selected_properties).await; let current_url = Rc::clone(&current_url);
async move {
save_item_to_db(new_item, selected_properties, current_url.to_string()).await;
}
}); });
} }
log!("Items updated: {:?}", items); log!("Items updated: {:?}", items);
}); });
}; })};
// List of properties to display as rows // List of properties to display as rows
let properties = vec!["Name", "Description"]; let properties = vec!["Name", "Description"];
@ -591,11 +612,13 @@ pub fn ItemsList(
</thead> </thead>
<tbody> <tbody>
{properties.into_iter().map(|property| { {properties.into_iter().map(|property| {
let update_item_cloned = Arc::clone(&update_item);
log!("Rendering property: {}", property); log!("Rendering property: {}", property);
view! { view! {
<tr> <tr>
<td>{ property }</td> <td>{ property }</td>
{move || items.get().iter().enumerate().map(|(index, item)| { {move || items.get().iter().enumerate().map(|(index, item)| {
let update_item_clone = Arc::clone(&update_item_cloned);
view! { view! {
<td> <td>
{match property { {match property {
@ -604,7 +627,7 @@ pub fn ItemsList(
<EditableCell <EditableCell
value=item.name.clone() value=item.name.clone()
on_input=move |value| { on_input=move |value| {
update_item(index, "name", value.clone()); update_item_clone(index, "name", value.clone());
fetch_wikidata_suggestions(format!("name-{}", index), value); fetch_wikidata_suggestions(format!("name-{}", index), value);
} }
key=Arc::new(format!("name-{}", index)) key=Arc::new(format!("name-{}", index))
@ -707,7 +730,7 @@ pub fn ItemsList(
"Description" => view! { "Description" => view! {
<EditableCell <EditableCell
value=item.description.clone() value=item.description.clone()
on_input=move |value| update_item(index, "description", value) on_input=move |value| update_item_clone(index, "description", value)
key=Arc::new(format!("description-{}", index)) key=Arc::new(format!("description-{}", index))
focused_cell=focused_cell focused_cell=focused_cell
set_focused_cell=set_focused_cell.clone() set_focused_cell=set_focused_cell.clone()
@ -731,9 +754,14 @@ pub fn ItemsList(
} }
}).collect::<Vec<_>>()} }).collect::<Vec<_>>()}
// Dynamically adding custom properties as columns // Dynamically adding custom properties as columns
{move || { {{
let update_item_outer = Arc::clone(&update_item);
move || {
let update_item = Arc::clone(&update_item_outer);
let custom_props = custom_properties.get().clone(); let custom_props = custom_properties.get().clone();
custom_props.into_iter().map(move |property| { custom_props.into_iter().map(move |property| {
let update_item_inner = Arc::clone(&update_item);
let normalized_property = property.replace("http://www.wikidata.org/prop/", ""); let normalized_property = property.replace("http://www.wikidata.org/prop/", "");
let property_label = property_labels.get().get(&normalized_property).cloned().unwrap_or_else(|| normalized_property.clone()); let property_label = property_labels.get().get(&normalized_property).cloned().unwrap_or_else(|| normalized_property.clone());
log!("Rendering property: {} -> {}", normalized_property, property_label); log!("Rendering property: {} -> {}", normalized_property, property_label);
@ -759,14 +787,16 @@ pub fn ItemsList(
}>{ "Delete" }</button> }>{ "Delete" }</button>
</td> </td>
{move || { {move || {
let update_item_cell = Arc::clone(&update_item_inner);
let property_clone_for_cells = normalized_property.clone(); let property_clone_for_cells = normalized_property.clone();
items.get().iter().enumerate().map(move |(index, item)| { items.get().iter().enumerate().map(move |(index, item)| {
let property_clone_for_closure = property_clone_for_cells.clone(); let update_item_cell = Arc::clone(&update_item_cell);
let property_clone_for_closure = property_clone_for_cells.clone();
view! { view! {
<td> <td>
<EditableCell <EditableCell
value=item.custom_properties.get(&property_clone_for_closure).cloned().unwrap_or_default() value=item.custom_properties.get(&property_clone_for_closure).cloned().unwrap_or_default()
on_input=move |value| update_item(index, &property_clone_for_closure, value) on_input=move |value| update_item_cell(index, &property_clone_for_closure, value)
key=Arc::new(format!("custom-{}-{}", property_clone_for_cells, index)) key=Arc::new(format!("custom-{}-{}", property_clone_for_cells, index))
focused_cell=focused_cell focused_cell=focused_cell
set_focused_cell=set_focused_cell.clone() set_focused_cell=set_focused_cell.clone()
@ -782,7 +812,7 @@ pub fn ItemsList(
} }
</tr> </tr>
} }
}).collect::<Vec<_>>() }).collect::<Vec<_>>()}
}} }}
</tbody> </tbody>
</table> </table>