use err ctx
This commit is contained in:
parent
5b49586da3
commit
d39596da77
@ -1,10 +1,13 @@
|
|||||||
|
use crate::components::error::error_provider::ErrorContext;
|
||||||
use crate::services::rest::RestService;
|
use crate::services::rest::RestService;
|
||||||
use common::Achievement;
|
use common::Achievement;
|
||||||
use common::ToggleAchievement;
|
use common::ToggleAchievement;
|
||||||
|
use std::rc::Rc;
|
||||||
use wasm_bindgen_futures::spawn_local;
|
use wasm_bindgen_futures::spawn_local;
|
||||||
use yew::classes;
|
use yew::classes;
|
||||||
use yew::function_component;
|
use yew::function_component;
|
||||||
use yew::html;
|
use yew::html;
|
||||||
|
use yew::use_context;
|
||||||
use yew::Callback;
|
use yew::Callback;
|
||||||
use yew::Html;
|
use yew::Html;
|
||||||
use yew::Properties;
|
use yew::Properties;
|
||||||
@ -17,6 +20,8 @@ pub struct Props {
|
|||||||
|
|
||||||
#[function_component]
|
#[function_component]
|
||||||
pub fn AchievementComponent(props: &Props) -> Html {
|
pub fn AchievementComponent(props: &Props) -> Html {
|
||||||
|
let err_ctx = Rc::new(use_context::<ErrorContext>());
|
||||||
|
|
||||||
let Achievement {
|
let Achievement {
|
||||||
goal,
|
goal,
|
||||||
completed,
|
completed,
|
||||||
@ -28,10 +33,15 @@ pub fn AchievementComponent(props: &Props) -> Html {
|
|||||||
|
|
||||||
let onclick_toggle = Callback::from(move |_| {
|
let onclick_toggle = Callback::from(move |_| {
|
||||||
log::info!("button click, toggling achievement");
|
log::info!("button click, toggling achievement");
|
||||||
|
let err_ctx = Rc::clone(&err_ctx);
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
match RestService::toggle_achievement(ToggleAchievement { uuid }).await {
|
match RestService::toggle_achievement(ToggleAchievement { uuid }).await {
|
||||||
Ok(_response) => {}
|
Ok(_response) => {}
|
||||||
Err(_err) => {}
|
Err(err) => {
|
||||||
|
if let Some(err_ctx) = &*err_ctx {
|
||||||
|
err_ctx.dispatch(err.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
use crate::components::error::error_provider::ErrorContext;
|
||||||
use crate::services::confirm::ConfirmService;
|
use crate::services::confirm::ConfirmService;
|
||||||
use crate::services::rest::RestService;
|
use crate::services::rest::RestService;
|
||||||
use common::DeleteAchievement;
|
use common::DeleteAchievement;
|
||||||
use common::DeleteMilestone;
|
use common::DeleteMilestone;
|
||||||
use common::UpdateAchievementTimeOfReveal;
|
use common::UpdateAchievementTimeOfReveal;
|
||||||
|
use std::rc::Rc;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use wasm_bindgen_futures::spawn_local;
|
use wasm_bindgen_futures::spawn_local;
|
||||||
use yew::function_component;
|
use yew::function_component;
|
||||||
@ -27,8 +29,9 @@ pub fn Admin() -> Html {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, a)| (idx + 1, a))
|
.map(|(idx, a)| (idx + 1, a))
|
||||||
.map(|(n, a)| {
|
.map(|(n, a)| {
|
||||||
|
let uuid = a.uuid.to_string();
|
||||||
html! {
|
html! {
|
||||||
<Achievement number={n} achievement={a} />
|
<Achievement key={uuid} number={n} achievement={a} />
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Html>();
|
.collect::<Html>();
|
||||||
@ -48,7 +51,10 @@ pub fn Admin() -> Html {
|
|||||||
milestones.sort_by_key(|m| m.goal);
|
milestones.sort_by_key(|m| m.goal);
|
||||||
let milestones = milestones
|
let milestones = milestones
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|m| html! { <Milestone milestone={m}/> })
|
.map(|m| {
|
||||||
|
let uuid = m.uuid.to_string();
|
||||||
|
html! { <Milestone key={uuid} milestone={m}/> }
|
||||||
|
})
|
||||||
.collect::<Html>();
|
.collect::<Html>();
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
@ -93,6 +99,7 @@ struct AchievementProps {
|
|||||||
|
|
||||||
#[function_component]
|
#[function_component]
|
||||||
fn Achievement(props: &AchievementProps) -> Html {
|
fn Achievement(props: &AchievementProps) -> Html {
|
||||||
|
let err_ctx = Rc::new(use_context::<ErrorContext>());
|
||||||
let achievement = &props.achievement;
|
let achievement = &props.achievement;
|
||||||
let uuid = achievement.uuid;
|
let uuid = achievement.uuid;
|
||||||
|
|
||||||
@ -108,6 +115,7 @@ fn Achievement(props: &AchievementProps) -> Html {
|
|||||||
let awaiting_response = awaiting_response.clone();
|
let awaiting_response = awaiting_response.clone();
|
||||||
let timed_reveal_enabled = timed_reveal_enabled.clone();
|
let timed_reveal_enabled = timed_reveal_enabled.clone();
|
||||||
let input_time = input_time.clone();
|
let input_time = input_time.clone();
|
||||||
|
let err_ctx = Rc::clone(&err_ctx);
|
||||||
Callback::from(move |e: web_sys::SubmitEvent| {
|
Callback::from(move |e: web_sys::SubmitEvent| {
|
||||||
e.prevent_default();
|
e.prevent_default();
|
||||||
|
|
||||||
@ -129,8 +137,16 @@ fn Achievement(props: &AchievementProps) -> Html {
|
|||||||
};
|
};
|
||||||
awaiting_response.set(true);
|
awaiting_response.set(true);
|
||||||
let awaiting_response = awaiting_response.clone();
|
let awaiting_response = awaiting_response.clone();
|
||||||
|
let err_ctx = Rc::clone(&err_ctx);
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
let res = RestService::update_time_of_reveal(payload).await;
|
match RestService::update_time_of_reveal(payload).await {
|
||||||
|
Ok(_response) => {}
|
||||||
|
Err(err) => {
|
||||||
|
if let Some(err_ctx) = &*err_ctx {
|
||||||
|
err_ctx.dispatch(err.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
awaiting_response.set(false);
|
awaiting_response.set(false);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -163,10 +179,15 @@ fn Achievement(props: &AchievementProps) -> Html {
|
|||||||
}
|
}
|
||||||
log::info!("Delete achievement confirmed.");
|
log::info!("Delete achievement confirmed.");
|
||||||
|
|
||||||
|
let err_ctx = Rc::clone(&err_ctx);
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
match RestService::delete_achievement(DeleteAchievement { uuid }).await {
|
match RestService::delete_achievement(DeleteAchievement { uuid }).await {
|
||||||
Ok(_response) => {}
|
Ok(_response) => {}
|
||||||
Err(_err) => {}
|
Err(err) => {
|
||||||
|
if let Some(err_ctx) = &*err_ctx {
|
||||||
|
err_ctx.dispatch(err.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -192,7 +213,7 @@ fn Achievement(props: &AchievementProps) -> Html {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
// Timed reveal form
|
// Timed reveal form
|
||||||
<form onsubmit={onsubmit_timed_reveal}>
|
<form onsubmit={onsubmit_timed_reveal} style="margin-left: 30px">
|
||||||
// Timed reveal: Enable checkbox
|
// Timed reveal: Enable checkbox
|
||||||
<label>
|
<label>
|
||||||
<span class="label-body" style="margin-right: 0.5rem; font-weight: bold"><i class="fas fa-clock" style="padding-right: 0.5em"/>{"Enable Timed Reveal:"}</span>
|
<span class="label-body" style="margin-right: 0.5rem; font-weight: bold"><i class="fas fa-clock" style="padding-right: 0.5em"/>{"Enable Timed Reveal:"}</span>
|
||||||
@ -215,23 +236,27 @@ fn Achievement(props: &AchievementProps) -> Html {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[function_component]
|
#[function_component]
|
||||||
fn Milestone(props: &MilestoneProps) -> Html {
|
fn Milestone(props: &MilestoneProps) -> Html {
|
||||||
|
let err_ctx = Rc::new(use_context::<ErrorContext>());
|
||||||
let uuid = props.milestone.uuid;
|
let uuid = props.milestone.uuid;
|
||||||
let onclick_delete = Callback::from(move |_| {
|
let onclick_delete = Callback::from(move |_| {
|
||||||
if !ConfirmService::confirm("Are you sure you want to delete?") {
|
if !ConfirmService::confirm("Are you sure you want to delete?") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let err_ctx = Rc::clone(&err_ctx);
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
match RestService::delete_milestone(DeleteMilestone { uuid }).await {
|
match RestService::delete_milestone(DeleteMilestone { uuid }).await {
|
||||||
Ok(_response) => {}
|
Ok(_response) => {}
|
||||||
Err(_err) => {}
|
Err(err) => {
|
||||||
|
if let Some(err_ctx) = &*err_ctx {
|
||||||
|
err_ctx.dispatch(err.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::error::error_provider::ErrorContext;
|
use super::error::error_provider::get_error_context;
|
||||||
use crate::services::rest::RestService;
|
use crate::services::rest::RestService;
|
||||||
use crate::services::rest::RestServiceError;
|
use crate::services::rest::RestServiceError;
|
||||||
use common::CreateAchievement;
|
use common::CreateAchievement;
|
||||||
@ -66,14 +66,12 @@ impl Component for CreateAchievementComponent {
|
|||||||
match result {
|
match result {
|
||||||
Ok(_response) => {
|
Ok(_response) => {
|
||||||
let nav = ctx.link().navigator().unwrap();
|
let nav = ctx.link().navigator().unwrap();
|
||||||
nav.push(&crate::Route::Root);
|
nav.push(&crate::Route::Admin);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let (error_context, _context_listener) = ctx
|
if let Some(err_ctx) = get_error_context(ctx) {
|
||||||
.link()
|
err_ctx.dispatch(err.to_string());
|
||||||
.context(Callback::from(|_: ErrorContext| ()))
|
}
|
||||||
.expect("No Error Context Provided");
|
|
||||||
error_context.dispatch(err.to_string());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.awaiting_response = false;
|
self.awaiting_response = false;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::error::error_provider::ErrorContext;
|
use super::error::error_provider::get_error_context;
|
||||||
use crate::services::rest::RestService;
|
use crate::services::rest::RestService;
|
||||||
use crate::services::rest::RestServiceError;
|
use crate::services::rest::RestServiceError;
|
||||||
use common::CreateMilestone;
|
use common::CreateMilestone;
|
||||||
@ -67,14 +67,12 @@ impl Component for CreateMilestoneComponent {
|
|||||||
match result {
|
match result {
|
||||||
Ok(_response) => {
|
Ok(_response) => {
|
||||||
let nav = ctx.link().navigator().unwrap();
|
let nav = ctx.link().navigator().unwrap();
|
||||||
nav.push(&crate::Route::Root);
|
nav.push(&crate::Route::Admin)
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let (error_context, _context_listener) = ctx
|
if let Some(err_ctx) = get_error_context(ctx) {
|
||||||
.link()
|
err_ctx.dispatch(err.to_string());
|
||||||
.context(Callback::from(|_: ErrorContext| ()))
|
}
|
||||||
.expect("No Error Context Provided");
|
|
||||||
error_context.dispatch(err.to_string());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.awaiting_response = false;
|
self.awaiting_response = false;
|
||||||
@ -92,7 +90,7 @@ impl Component for CreateMilestoneComponent {
|
|||||||
let nav = ctx.link().navigator().unwrap();
|
let nav = ctx.link().navigator().unwrap();
|
||||||
|
|
||||||
let onclick_go_back = Callback::from(move |_: web_sys::MouseEvent| {
|
let onclick_go_back = Callback::from(move |_: web_sys::MouseEvent| {
|
||||||
nav.push(&crate::Route::Root);
|
nav.push(&crate::Route::Admin);
|
||||||
});
|
});
|
||||||
|
|
||||||
let onsubmit = link.callback(|e: web_sys::SubmitEvent| {
|
let onsubmit = link.callback(|e: web_sys::SubmitEvent| {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! This is the UI component that subscribes to and displays errors.
|
||||||
|
|
||||||
use super::error_provider::ErrorContext;
|
use super::error_provider::ErrorContext;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
@ -41,3 +41,10 @@ pub fn ErrorProvider(props: &ErrorProviderProps) -> Html {
|
|||||||
</ContextProvider<ErrorContext>>
|
</ContextProvider<ErrorContext>>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper for struct components to get the error context
|
||||||
|
pub fn get_error_context(ctx: &Context<impl yew::Component>) -> Option<ErrorContext> {
|
||||||
|
ctx.link()
|
||||||
|
.context(Callback::from(|_: ErrorContext| ()))
|
||||||
|
.map(|(error_context, _context_handle)| error_context)
|
||||||
|
}
|
||||||
|
@ -3,11 +3,9 @@ use crate::components::milestone::MilestoneComponent;
|
|||||||
use crate::util::group_achievements::group_achievements;
|
use crate::util::group_achievements::group_achievements;
|
||||||
use yew::functional::*;
|
use yew::functional::*;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew_router::prelude::*;
|
|
||||||
|
|
||||||
#[function_component]
|
#[function_component]
|
||||||
pub fn Root() -> Html {
|
pub fn Root() -> Html {
|
||||||
let nav = use_navigator().expect("cannot get navigator");
|
|
||||||
let app_state = use_context::<crate::AppState>().expect("no app state ctx found");
|
let app_state = use_context::<crate::AppState>().expect("no app state ctx found");
|
||||||
|
|
||||||
let current_time: chrono::NaiveTime = chrono::Local::now().time();
|
let current_time: chrono::NaiveTime = chrono::Local::now().time();
|
||||||
@ -21,7 +19,7 @@ pub fn Root() -> Html {
|
|||||||
if let Some(time_of_reveal) = time_of_reveal {
|
if let Some(time_of_reveal) = time_of_reveal {
|
||||||
let s = if time_of_reveal > current_time {
|
let s = if time_of_reveal > current_time {
|
||||||
format!(
|
format!(
|
||||||
"{} more revealed at {}!",
|
"Next {} revealed at {}!",
|
||||||
group.len(),
|
group.len(),
|
||||||
time_of_reveal.format("%H:%M")
|
time_of_reveal.format("%H:%M")
|
||||||
)
|
)
|
||||||
@ -38,8 +36,9 @@ pub fn Root() -> Html {
|
|||||||
}
|
}
|
||||||
for a in group {
|
for a in group {
|
||||||
n += 1;
|
n += 1;
|
||||||
|
let uuid = a.uuid.to_string();
|
||||||
let html = html! {
|
let html = html! {
|
||||||
<AchievementComponent number={n} achievement={a} />
|
<AchievementComponent key={uuid} number={n} achievement={a} />
|
||||||
};
|
};
|
||||||
achievements_html.push(html);
|
achievements_html.push(html);
|
||||||
}
|
}
|
||||||
@ -55,7 +54,7 @@ pub fn Root() -> Html {
|
|||||||
|
|
||||||
let mut milestones = app_state.state.milestones.clone();
|
let mut milestones = app_state.state.milestones.clone();
|
||||||
milestones.sort_by_key(|m| m.goal);
|
milestones.sort_by_key(|m| m.goal);
|
||||||
let milestones = milestones.into_iter().map(|m| html! { <MilestoneComponent milestone={m} completed_achievements={completed_achievements} /> }).collect::<Html>();
|
let milestones = milestones.into_iter().map(|m| {let uuid = m.uuid.to_string(); html! { <MilestoneComponent key={uuid} milestone={m} completed_achievements={completed_achievements} /> }}).collect::<Html>();
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
|
@ -41,7 +41,7 @@ impl RestService {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
if let Ok(rest_response) = response.json::<RestResponse<T>>().await {
|
if let Ok(rest_response) = response.json::<RestResponse<T>>().await {
|
||||||
return rest_response.map_err(Into::into);
|
return rest_response.map_err(RestServiceError::RestError);
|
||||||
}
|
}
|
||||||
|
|
||||||
let err = RestServiceError::UnexpectedResponse(response);
|
let err = RestServiceError::UnexpectedResponse(response);
|
||||||
|
@ -38,7 +38,7 @@ mod tests {
|
|||||||
let time1 = NaiveTime::from_hms_opt(12, 0, 0).unwrap();
|
let time1 = NaiveTime::from_hms_opt(12, 0, 0).unwrap();
|
||||||
let time2 = NaiveTime::from_hms_opt(13, 0, 0).unwrap();
|
let time2 = NaiveTime::from_hms_opt(13, 0, 0).unwrap();
|
||||||
|
|
||||||
let mut achievements = vec![
|
let achievements = vec![
|
||||||
Achievement {
|
Achievement {
|
||||||
goal: "Goal 1".to_string(),
|
goal: "Goal 1".to_string(),
|
||||||
completed: true,
|
completed: true,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user