error component wip
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
use super::error::error_provider::ErrorContext;
|
||||
use crate::services::rest::RestService;
|
||||
use crate::services::rest::RestServiceError;
|
||||
use common::CreateMilestone;
|
||||
use wasm_bindgen::JsCast;
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
@@ -13,6 +15,7 @@ use yew_router::scope_ext::RouterScopeExt;
|
||||
#[derive(Debug)]
|
||||
pub enum Msg {
|
||||
Submit,
|
||||
SubmitResult(Result<(), RestServiceError>),
|
||||
UpdateInput(String),
|
||||
}
|
||||
|
||||
@@ -41,7 +44,7 @@ impl Component for CreateMilestoneComponent {
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &yew::Context<Self>, msg: Self::Message) -> bool {
|
||||
fn update(&mut self, ctx: &yew::Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
Msg::Submit => {
|
||||
log::info!("Creating achievement");
|
||||
@@ -49,16 +52,32 @@ impl Component for CreateMilestoneComponent {
|
||||
|
||||
let goal = goal as usize;
|
||||
let payload = CreateMilestone { goal };
|
||||
let link = ctx.link().clone();
|
||||
spawn_local(async move {
|
||||
match RestService::create_milestone(payload).await {
|
||||
Ok(_response) => {}
|
||||
Err(_err) => {}
|
||||
}
|
||||
let res = RestService::create_milestone(payload).await;
|
||||
link.send_message(Msg::SubmitResult(res));
|
||||
});
|
||||
self.submitted = true;
|
||||
|
||||
true
|
||||
}
|
||||
Msg::SubmitResult(result) => {
|
||||
match result {
|
||||
Ok(_response) => {
|
||||
let nav = ctx.link().navigator().unwrap();
|
||||
nav.push(&crate::Route::Root);
|
||||
}
|
||||
Err(err) => {
|
||||
let (error_context, _context_listener) = ctx
|
||||
.link()
|
||||
.context(Callback::from(|_: ErrorContext| ()))
|
||||
.expect("No Error Context Provided");
|
||||
log::info!("dispatching error");
|
||||
error_context.dispatch(err.to_string());
|
||||
}
|
||||
};
|
||||
true
|
||||
}
|
||||
Msg::UpdateInput(value) => {
|
||||
self.input_value = value;
|
||||
true
|
||||
|
||||
68
crates/frontend/src/components/error/error_component.rs
Normal file
68
crates/frontend/src/components/error/error_component.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
use super::error_provider::ErrorContext;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub enum Msg {
|
||||
ErrorContextUpdated(ErrorContext),
|
||||
HideError,
|
||||
}
|
||||
|
||||
pub struct ErrorComponent {
|
||||
error: Option<String>,
|
||||
_context_listener: ContextHandle<ErrorContext>,
|
||||
}
|
||||
|
||||
impl Component for ErrorComponent {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
let (error_context, context_listener) = ctx
|
||||
.link()
|
||||
.context(ctx.link().callback(Msg::ErrorContextUpdated))
|
||||
.expect("No Error Context Provided");
|
||||
Self {
|
||||
error: error_context.value.clone(),
|
||||
_context_listener: context_listener,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
Msg::ErrorContextUpdated(error_context) => {
|
||||
self.error = error_context.value.clone();
|
||||
true
|
||||
}
|
||||
Msg::HideError => {
|
||||
self.error = None;
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let onclick_hide = ctx.link().callback(|_| Msg::HideError);
|
||||
html! {
|
||||
<div>
|
||||
{ self.view_error(onclick_hide) }
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ErrorComponent {
|
||||
fn view_error(&self, onclick_hide: Callback<MouseEvent>) -> Html {
|
||||
match &self.error {
|
||||
Some(error_msg) => {
|
||||
html! {
|
||||
<div class="error-message">
|
||||
{ error_msg }
|
||||
<button onclick={onclick_hide}>
|
||||
{ "Hide" }
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
None => html! {},
|
||||
}
|
||||
}
|
||||
}
|
||||
34
crates/frontend/src/components/error/error_provider.rs
Normal file
34
crates/frontend/src/components/error/error_provider.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
use std::rc::Rc;
|
||||
use yew::prelude::*;
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Error {
|
||||
pub value: Option<String>,
|
||||
}
|
||||
|
||||
impl Reducible for Error {
|
||||
type Action = String;
|
||||
|
||||
fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
|
||||
Error { value: Some(action) }.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub type ErrorContext = UseReducerHandle<Error>;
|
||||
|
||||
#[derive(Properties, Debug, PartialEq)]
|
||||
pub struct ErrorProviderProps {
|
||||
#[prop_or_default]
|
||||
pub children: Children,
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
pub fn ErrorProvider(props: &ErrorProviderProps) -> Html {
|
||||
let err = use_reducer(Default::default);
|
||||
|
||||
html! {
|
||||
<ContextProvider<ErrorContext> context={err}>
|
||||
{props.children.clone()}
|
||||
</ContextProvider<ErrorContext>>
|
||||
}
|
||||
}
|
||||
2
crates/frontend/src/components/error/mod.rs
Normal file
2
crates/frontend/src/components/error/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod error_component;
|
||||
pub mod error_provider;
|
||||
@@ -1,4 +1,8 @@
|
||||
use crate::services::confirm::ConfirmService;
|
||||
use crate::services::rest::RestService;
|
||||
use common::DeleteMilestone;
|
||||
use common::Milestone;
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
use yew::prelude::*;
|
||||
|
||||
#[derive(Properties, Clone, PartialEq)]
|
||||
@@ -9,6 +13,8 @@ pub struct Props {
|
||||
|
||||
#[function_component(MilestoneComponent)]
|
||||
pub fn milestone_component(props: &Props) -> Html {
|
||||
let confirm_service = use_memo(|_| ConfirmService, ());
|
||||
|
||||
let unfilled = props.milestone.goal - props.completed_achievements.min(props.milestone.goal);
|
||||
let filled = props.completed_achievements.min(props.milestone.goal);
|
||||
|
||||
@@ -24,14 +30,32 @@ pub fn milestone_component(props: &Props) -> Html {
|
||||
.take(filled)
|
||||
.collect::<Html>();
|
||||
|
||||
let uuid = props.milestone.uuid;
|
||||
let onclick_delete = Callback::from(move |_| {
|
||||
if !confirm_service.confirm("Are you sure you want to delete?") {
|
||||
return;
|
||||
}
|
||||
log::info!("Delete achievement confirmed.");
|
||||
|
||||
spawn_local(async move {
|
||||
match RestService::delete_milestone(DeleteMilestone { uuid }).await {
|
||||
Ok(_response) => {}
|
||||
Err(_err) => {}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
html! {
|
||||
<div class="row">
|
||||
<p style="text-align: center" class="u-full-width">
|
||||
{format!("{} / {}", props.completed_achievements, props.milestone.goal)}
|
||||
<br />
|
||||
{filled_stars}
|
||||
{unfilled_stars}
|
||||
</p>
|
||||
<div class="row flex">
|
||||
<p style="text-align: center" class="flex-grow">
|
||||
{format!("{} / {}", props.completed_achievements, props.milestone.goal)}
|
||||
<br />
|
||||
{filled_stars}
|
||||
{unfilled_stars}
|
||||
</p>
|
||||
<div class="flex-intrinsic-size">
|
||||
<button onclick={onclick_delete} class="button color-danger"><i class="fas fa-trash"/></button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,5 +2,6 @@ pub mod achievement;
|
||||
pub mod admin;
|
||||
pub mod create_achievement;
|
||||
pub mod create_milestone;
|
||||
pub mod error;
|
||||
pub mod milestone;
|
||||
pub mod root;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use crate::components::error::error_component::ErrorComponent;
|
||||
use crate::components::error::error_provider::ErrorProvider;
|
||||
use components::admin::Admin;
|
||||
use components::create_achievement::CreateAchievementComponent;
|
||||
use components::create_milestone::CreateMilestoneComponent;
|
||||
@@ -49,11 +51,14 @@ pub fn App() -> Html {
|
||||
|
||||
html! {
|
||||
<ContextProvider<AppState> context={(*ctx).clone()}>
|
||||
<BrowserRouter>
|
||||
<div class="container" style="margin-top: 5%; margin-bottom: 25%">
|
||||
<ErrorProvider>
|
||||
<div class="container" style="margin-top: 5%; margin-bottom: 25%">
|
||||
<ErrorComponent />
|
||||
<BrowserRouter>
|
||||
<Switch<Route> render={switch}/>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
</BrowserRouter>
|
||||
</div>
|
||||
</ErrorProvider>
|
||||
</ContextProvider<AppState>>
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user