flams_web_utils/components/
errors.rs

1use std::borrow::Cow;
2
3use thaw::{ToastOptions, ToastPosition, ToasterInjection, MessageBar,MessageBarBody,MessageBarIntent};
4use leptos::prelude::*;
5
6#[inline]
7pub fn display_error(err:Cow<'static,str>) -> impl leptos::IntoView {
8  #[cfg(any(feature="hydrate",feature="csr"))]
9  { error_toast(err.clone()); }
10  view!(<h3 style="color:red">"Error: "{err}</h3>)
11}
12
13pub fn message_action<
14  I: Clone+Send+Sync+'static,
15  O,
16  E:std::fmt::Display + Send + 'static,
17  V: std::fmt::Display + Send + 'static,
18  Fut: std::future::Future<Output = Result<O,E>> + Send
19>(
20  run:impl Fn(I) -> Fut + Send + Sync + Clone + 'static,
21  msg:impl Fn(O) -> V + Send + Sync + Clone + 'static
22) -> Action<I,()> {
23  let toaster = ToasterInjection::expect_context();
24  Action::new(move |args:&I| {
25    let run = run.clone();
26    let msg = msg.clone();
27    let args = args.clone();
28    async move {
29      match run(args).await {
30        Ok(r) => success_with_toaster(msg(r),toaster),
31        Err(e) => error_with_toaster(e,toaster),
32      }
33    }
34  })
35}
36
37pub fn waiting_message_action<
38I: Clone+Send+Sync+'static,
39O,
40E:std::fmt::Display + Send + 'static,
41V: std::fmt::Display + Send + 'static,
42Fut: std::future::Future<Output = Result<O,E>> + Send + 'static
43>(
44run:impl Fn(&I) -> Fut + Send + Sync + Clone + 'static,
45msg:impl Fn(O) -> V + Send + Sync + Clone + 'static
46) -> (Action<I,()>,impl IntoView) {
47  let toaster = ToasterInjection::expect_context();
48  waiting_action(run,move |o| success_with_toaster(msg(o),toaster))
49}
50
51pub fn waiting_action<
52I: Clone+Send+Sync+'static,
53O,
54E:std::fmt::Display + Send + 'static,
55Fut: std::future::Future<Output = Result<O,E>> + Send + 'static
56>(
57run:impl Fn(&I) -> Fut + Send + Sync + Clone + 'static,
58msg:impl Fn(O) + Send + Sync + Clone + 'static
59) -> (Action<I,()>,impl IntoView) {
60  use thaw::{Dialog,DialogSurface,DialogBody};
61  use crate::components::Spinner;
62  let toaster = ToasterInjection::expect_context();
63  let open = RwSignal::new(false);
64  let a = Action::new(move |args:&I| {
65    let r = run(args);
66    open.set(true);
67    let msg = msg.clone();
68    async move {
69      match r.await {
70        Ok(r) => {
71          open.set(false);
72          msg(r);
73        }
74        Err(e) => {
75          open.set(false);
76          error_with_toaster(e,toaster);
77        }
78      }
79    }
80  });
81  (a,view!{<Dialog mask_closeable=false close_on_esc=false open=open ><DialogSurface><DialogBody><Spinner/></DialogBody></DialogSurface></Dialog>})
82}
83
84#[inline]
85pub fn error_toast(err:impl std::fmt::Display + Send + 'static) {
86  let toaster = ToasterInjection::expect_context();
87  error_with_toaster(err, toaster);
88}
89
90#[inline]
91pub fn success_toast(msg:impl std::fmt::Display + Send + 'static) {
92  let toaster = ToasterInjection::expect_context();
93  success_with_toaster(msg, toaster);
94}
95
96pub fn error_with_toaster(err:impl std::fmt::Display + Send + 'static,toaster:ToasterInjection) {
97  tracing::error!("{err}");
98  toaster.dispatch_toast(
99    move || view!{
100      <MessageBar intent=MessageBarIntent::Error>
101        <MessageBarBody>{err.to_string()}</MessageBarBody>
102      </MessageBar>
103    },
104    ToastOptions::default().with_position(ToastPosition::Top)
105  );
106}
107
108fn success_with_toaster(msg:impl std::fmt::Display + Send + 'static,toaster:ToasterInjection) {
109  tracing::info!("{msg}");
110  toaster.dispatch_toast(
111    move || view!{
112      <MessageBar intent=MessageBarIntent::Success>
113        <MessageBarBody>{msg.to_string()}</MessageBarBody>
114      </MessageBar>
115    },
116    ToastOptions::default().with_position(ToastPosition::Top)
117  );
118}