feat: allow reactive updates of UI with inserted file names

This commit is contained in:
alphafetus committed 2026-03-02 12:29:49 -05:00
1 parent 1bccecdc72
commit 6f16bbe311
2 files changed
+31 -30

No files matched your search

+13 -20
View File
@@ -18,12 +18,12 @@ pub fn FileDrop(#[prop(into)] name: String, #[prop(into)] form_id: String) -> im
let form_id = StoredValue::new(form_id); let form_id = StoredValue::new(form_id);
let auth = expect_context::<AuthSignal>(); let auth = expect_context::<AuthSignal>();
let upload_action = StoredValue::new(Action::new(|form_data: &FormData| { let upload_action = Action::new(|form_data: &FormData| {
let form_data = form_data.clone(); let form_data = form_data.clone();
async move { upload_file(form_data.into()).await } async move { upload_file(form_data.into()).await }
})); });
let uploading = upload_action.get_value().pending(); let uploading = upload_action.pending();
let upload_files = Callback::new(move |files: Vec<File>| { let upload_files = Callback::new(move |files: Vec<File>| {
let form_data = FormData::new().unwrap(); let form_data = FormData::new().unwrap();
@@ -52,7 +52,7 @@ pub fn FileDrop(#[prop(into)] name: String, #[prop(into)] form_id: String) -> im
} }
// Upload file to server. // Upload file to server.
upload_action.get_value().dispatch(form_data); upload_action.dispatch(form_data);
}); });
let UseDropZoneReturn { let UseDropZoneReturn {
@@ -64,11 +64,6 @@ pub fn FileDrop(#[prop(into)] name: String, #[prop(into)] form_id: String) -> im
.on_drop(move |ev| { .on_drop(move |ev| {
let file = ev.files.first().unwrap(); let file = ev.files.first().unwrap();
// Update file list
file_name_list.update(|list| {
list.push(file.name());
});
upload_files.run(vec![file.to_owned()]); upload_files.run(vec![file.to_owned()]);
}), }),
); );
@@ -88,20 +83,18 @@ pub fn FileDrop(#[prop(into)] name: String, #[prop(into)] form_id: String) -> im
}) })
.unwrap_or_default(); .unwrap_or_default();
file_name_list.update({
let files = files.clone();
|list| {
for file in files {
if !list.iter().any(|f| *f == file.name()) {
list.push(file.name());
}
}
}
});
upload_files.run(files); upload_files.run(files);
}; };
// Add file names to the list when upload_action is successful.
Effect::new(move || {
if let Some(Ok(uploaded_file_name)) = upload_action.value().get() {
file_name_list.update(|list| {
list.push(uploaded_file_name);
});
}
});
// let on_click_file_delete = move |file_name, form_id| { // let on_click_file_delete = move |file_name, form_id| {
// //
// }; // };
+18 -10
View File
@@ -3,7 +3,7 @@ use leptos::prelude::*;
use server_fn::codec::{MultipartData, MultipartFormData}; use server_fn::codec::{MultipartData, MultipartFormData};
#[server(input = MultipartFormData)] #[server(input = MultipartFormData)]
pub async fn upload_file(data: MultipartData) -> Result<(), ServerFnError> { pub async fn upload_file(data: MultipartData) -> Result<String, ServerFnError> {
use super::{MAIN_TABLE_NAME, S3_BUCKET_NAME}; use super::{MAIN_TABLE_NAME, S3_BUCKET_NAME};
use crate::pages::api::tokens::validate_and_get_token_info; use crate::pages::api::tokens::validate_and_get_token_info;
use crate::utils::server::create_aws_config; use crate::utils::server::create_aws_config;
@@ -89,31 +89,39 @@ pub async fn upload_file(data: MultipartData) -> Result<(), ServerFnError> {
"SK".to_string(), "SK".to_string(),
AttributeValue::S(format!("FILE#{form_id}#{input_name}")), AttributeValue::S(format!("FILE#{form_id}#{input_name}")),
) )
.item("file_name".to_string(), AttributeValue::S(file_name)) .item(
"file_name".to_string(),
AttributeValue::S(file_name.clone()),
)
.item("file_key".to_string(), AttributeValue::S(key.clone())) .item("file_key".to_string(), AttributeValue::S(key.clone()))
.send() .send()
.await .await
.map(|_| ()) .map_err(|e| {
.map_err(|e| ServerFnError::new(format!("Couldn't put file to Dynamo: {}", e.to_string()))); ServerFnError::new(format!(
"Couldn't put file to Dynamo, file rolled back: {}",
e.to_string()
))
});
if let Err(_) = dynamo_result { // If Dynamo fails, we want to handle the error by rolling back the file. Then, we return a failure.
// Roll back file insertion to S3. Only attempted on Dynamo insertion failure. if let Err(err) = dynamo_result {
s3_client s3_client
.delete_object() .delete_object()
.bucket("leptos-scholarships") .bucket("leptos-scholarships")
.key(&key) .key(&key)
.send() .send()
.await .await
.map(|_| ())
.map_err(|e| { .map_err(|e| {
ServerFnError::new(format!( ServerFnError::new(format!(
"Couldn't roll back S3 operation: {}", "Couldn't roll back S3 operation: {}",
e.to_string() e.to_string()
)) ))
}) })?;
} else {
dynamo_result return Err(err);
} }
Ok(file_name)
} }
#[server] #[server]