flams_web_utils/components/
errors.rs1use 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}