diff --git a/client/Cargo.toml b/client/Cargo.toml index 45308b4..79bbf0d 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -30,8 +30,11 @@ features = [ 'RequestMode', 'Response', 'Window', + 'Event', + 'InputEvent', 'FocusEvent', 'EventTarget', + 'FileList', 'HtmlElement', 'HtmlFormElement', 'HtmlInputElement', diff --git a/client/src/component/mod.rs b/client/src/component/mod.rs index 08090fd..9c8df78 100644 --- a/client/src/component/mod.rs +++ b/client/src/component/mod.rs @@ -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::*; diff --git a/client/src/component/uploader.rs b/client/src/component/uploader.rs new file mode 100644 index 0000000..6e4f807 --- /dev/null +++ b/client/src/component/uploader.rs @@ -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::().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); + 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! { +
+ {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! {
+ { "Upload success" } +
{upload_text.as_string().unwrap_or_default()}
+
} + } else if *is_uploading { + html! {
{ "Uploading..." }
} + } else { + html! { + + } + }} +
+ } +} diff --git a/client/src/container/home.rs b/client/src/container/home.rs index e32fc92..c38dedc 100644 --- a/client/src/container/home.rs +++ b/client/src/container/home.rs @@ -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, + input_keys: Vec, } pub enum Msg { - AddOne, - FileChange(Event), - Upload(JsValue), + Refresh, + UploadAddOne, + UploadEnd, } #[derive(Properties, PartialEq)] @@ -29,52 +36,39 @@ impl Component for HomeInner { type Properties = AppProps; fn create(ctx: &Context) -> Self { - HomeInner { refresh_index: 1, upload_result: None } + HomeInner { refresh_index: 1, input_keys: vec!{get_now()} } } fn update(&mut self, ctx: &Context, 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); - 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) -> 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! {

{"Upload"}

- -

- { 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! {

{upload_text.as_string().unwrap_or_default()}
} - } else { - html!{} - }} -

+ { list.into_iter().map(|i| html! { +
+ {i.clone()} + +
+ }).collect::()}
} }