Skip to content

Commit

Permalink
refactor: extract uploader
Browse files Browse the repository at this point in the history
  • Loading branch information
msyfls123 committed Apr 22, 2024
1 parent 937581b commit efb0437
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 44 deletions.
3 changes: 3 additions & 0 deletions client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ features = [
'RequestMode',
'Response',
'Window',
'Event',
'InputEvent',
'FocusEvent',
'EventTarget',
'FileList',
'HtmlElement',
'HtmlFormElement',
'HtmlInputElement',
Expand Down
2 changes: 2 additions & 0 deletions client/src/component/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ mod header;
mod login;
mod me;
pub mod bucket;
mod uploader;

pub use header::*;
pub use login::*;
pub use me::*;
pub use uploader::*;
84 changes: 84 additions & 0 deletions client/src/component/uploader.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use wasm_bindgen_futures::{spawn_local, JsFuture};
use web_sys::{console, Event, HtmlInputElement};
use wasm_bindgen::{closure::Closure, JsCast, JsValue};
use yew::{ html, prelude::function_component, use_callback, use_context, use_state, Callback, Html, Properties};
use js_sys::{Promise, JSON::stringify_with_replacer_and_space};

use crate::constants::app::AppContext;

#[derive(Properties, PartialEq)]
pub struct UploaderProps {
pub on_upload_start: Callback<()>,
pub on_upload_end: Callback<()>,
}

#[function_component(Uploader)]
pub fn uploader(props: &UploaderProps) -> Html {
// context
let app_ctx = use_context::<AppContext>().expect("no ctx found");
let cos_upload = app_ctx.upload_file;
// state
let upload_result = use_state(|| None);
let is_uploading = use_state(|| false);
// callbacks
let upload_start = use_callback(
(props.on_upload_start.clone(), is_uploading.clone()),
move |_, (on_start, uploading)| {
on_start.emit(());
uploading.set(true);
}
);
let upload_end = use_callback(
(props.on_upload_end.clone(), upload_result.clone()),
move |res, (on_end, res_state)| {
res_state.set(res);
on_end.emit(());
}
);

let on_upload = use_callback(upload_end.clone(), move |e: Event, upload_cb| {
upload_start.emit(());
let upload_cb = upload_cb.clone();
let result = cos_upload.call1(&JsValue::NULL, e.as_ref()).unwrap();
let promise = Promise::from(result);
let closure = Closure::once(Box::new(move |value: JsValue| {
console::log_1(&value);
upload_cb.emit(Some(value));
}) as Box<dyn FnMut(JsValue)>);
let promise = promise.then(&closure);
closure.forget();
let future = JsFuture::from(promise);
spawn_local(async {
match future.await {
Ok(_res) => {},
Err(err) => console::error_1(&err),
};
});
});


html! {
<div>
{if let Some(data) = upload_result.as_ref() {
let upload_text = stringify_with_replacer_and_space(&data, &JsValue::NULL, &JsValue::from_f64(4.0)).unwrap();
html! { <div>
{ "Upload success" }
<pre>{upload_text.as_string().unwrap_or_default()}</pre>
</div> }
} else if *is_uploading {
html! { <div>{ "Uploading..." }</div> }
} else {
html! {
<input type="file" onchange={move |e: Event| {
let target = e.target().unwrap();
let input_el: HtmlInputElement = target.dyn_into().unwrap();
let option_file = input_el.files().unwrap().item(0);
if let Some(file) = option_file {
on_upload.emit(e)
}
}} />
}
}}
</div>
}
}
81 changes: 37 additions & 44 deletions client/src/container/home.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
use js_sys::{Function, Promise, JSON::stringify_with_replacer_and_space};
use wasm_bindgen::{JsValue, prelude::Closure};
use wasm_bindgen_futures::{JsFuture, spawn_local};
use chrono::Utc;
use js_sys::Function;
use wasm_bindgen::JsValue;
use web_sys::console;
use yew::{prelude::*, virtual_dom::VNode,function_component};

use crate::component::graph::Graph;
use crate::component::bucket::Bucket;
use crate::component::Uploader;
use crate::constants::app::AppContext;

fn get_now() -> String {
let now = Utc::now();
let time: String = format!("{}", now);
return time
}

pub struct HomeInner {
refresh_index: i64,
upload_result: Option<JsValue>,
input_keys: Vec<String>,
}

pub enum Msg {
AddOne,
FileChange(Event),
Upload(JsValue),
Refresh,
UploadAddOne,
UploadEnd,
}

#[derive(Properties, PartialEq)]
Expand All @@ -29,52 +36,39 @@ impl Component for HomeInner {
type Properties = AppProps;

fn create(ctx: &Context<Self>) -> Self {
HomeInner { refresh_index: 1, upload_result: None }
HomeInner { refresh_index: 1, input_keys: vec!{get_now()} }
}

fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::AddOne => {
Msg::Refresh => {
self.refresh_index += 1;
true
},
Msg::Upload(value) => {
self.upload_result = Some(value);
self.refresh_index += 1;
Msg::UploadAddOne => {
self.input_keys = [vec!{get_now()}, self.input_keys.to_owned()].concat();
console::log_1(&JsValue::from_str("upload start"));
true
},
Msg::FileChange(e) => {
let callback = ctx.link().callback(|value: JsValue| {
Msg::Upload(value)
});
let func = &ctx.props().upload_file;
let result = func.call1(&JsValue::NULL, e.as_ref()).unwrap();
let promise = Promise::from(result);
let closure = Closure::once(Box::new(move |value: JsValue| {
console::log_1(&value);
callback.emit(value);
}) as Box<dyn FnMut(JsValue)>);
let promise = promise.then(&closure);
closure.forget();
let future = JsFuture::from(promise);
spawn_local(async {
match future.await {
Ok(_res) => {},
Err(err) => console::error_1(&err),
};
});
Msg::UploadEnd => {
console::log_1(&JsValue::from_str("upload end"));
self.refresh_index += 1;
true
}
},
}
}

fn view(&self, context: &Context<Self>) -> VNode {
let link = context.link();
let list = self.input_keys.clone();
let upload_start = link.callback(|_| Msg::UploadAddOne);
let upload_end = link.callback(|_| Msg::UploadEnd);

html! {
<div>
<div class="hidden">
<p>{ "refresh index " } { self.refresh_index } </p>
<button onclick={link.callback(|_| Msg::AddOne)}>{ "+1" }</button>
<button onclick={link.callback(|_| Msg::Refresh)}>{ "+1" }</button>
<p>{ "Hello world!" }</p>
<form class="hidden" method="post" enctype="multipart/form-data" action="/upload">
<input type="file" name="file"/>
Expand All @@ -84,16 +78,15 @@ impl Component for HomeInner {
</div>
<Bucket refresh_index={self.refresh_index as usize}/>
<h2>{"Upload"}</h2>
<input type="file" onchange={link.callback(|e| Msg::FileChange(e))}/>
<p>
{ if self.upload_result.is_some() {
let upload_json = self.upload_result.to_owned().unwrap();
let upload_text = stringify_with_replacer_and_space(&upload_json, &JsValue::NULL, &JsValue::from_f64(4.0)).unwrap();
html! { <pre>{upload_text.as_string().unwrap_or_default()}</pre>}
} else {
html!{}
}}
</p>
{ list.into_iter().map(|i| html! {
<div key={i.clone()}>
{i.clone()}
<Uploader
on_upload_start={upload_start.clone()}
on_upload_end={upload_end.clone()}
/>
</div>
}).collect::<Html>()}
</div>
}
}
Expand Down

0 comments on commit efb0437

Please sign in to comment.