Skip to main content

yew_bulma/
flash.rs

1use crate::wasm_utc_now;
2use chrono::{DateTime, Utc};
3use std::time::Duration;
4use yew::prelude::*;
5use yew::services::timeout::{TimeoutService, TimeoutTask};
6
7#[derive(Debug, Clone, Eq, PartialEq)]
8pub enum Kind {
9    Primary,
10    Link,
11    Info,
12    Success,
13    Warning,
14    Danger,
15}
16
17impl Kind {
18    pub fn css_class(&self) -> &'static str {
19        match self {
20            Kind::Primary => "is-primary",
21            Kind::Link => "is-link",
22            Kind::Info => "is-info",
23            Kind::Success => "is-success",
24            Kind::Warning => "is-warning",
25            Kind::Danger => "is-danger",
26        }
27    }
28}
29
30#[derive(Clone, Debug, Eq, PartialEq)]
31pub struct Message {
32    pub created_at: DateTime<Utc>,
33    pub kind: Kind,
34    pub content: String,
35    pub duration: Duration,
36}
37
38impl Message {
39    pub fn new<S: Into<String>, D: Into<Duration>>(kind: Kind, content: S, duration: D) -> Self {
40        Message {
41            kind,
42            created_at: wasm_utc_now(),
43            content: content.into(),
44            duration: duration.into(),
45        }
46    }
47}
48
49#[derive(Debug)]
50pub struct Flash {
51    link: ComponentLink<Self>,
52    props: Props,
53    timeout: TimeoutService,
54    hide_task: Option<TimeoutTask>,
55}
56
57#[derive(Debug, Clone, Properties)]
58pub struct Props {
59    #[prop_or_default]
60    pub message: Option<Message>,
61}
62
63pub enum ComponentMessage {
64    Hide,
65}
66
67impl Component for Flash {
68    type Message = ComponentMessage;
69    type Properties = Props;
70
71    fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
72        Self {
73            link,
74            props,
75            timeout: TimeoutService::default(),
76            hide_task: None,
77        }
78    }
79
80    fn update(&mut self, msg: Self::Message) -> ShouldRender {
81        match msg {
82            ComponentMessage::Hide => true,
83        }
84    }
85
86    fn change(&mut self, props: Self::Properties) -> ShouldRender {
87        if props.message != self.props.message {
88            if let Some(new_message) = &props.message {
89                self.hide_task = Some(TimeoutService::spawn(
90                    new_message.duration,
91                    self.link.callback(|_| ComponentMessage::Hide),
92                ));
93            }
94            self.props = props;
95            true
96        } else {
97            false
98        }
99    }
100
101    fn view(&self) -> Html {
102        if let Some(message) = &self.props.message {
103            let should_show = wasm_utc_now()
104                < message
105                    .created_at
106                    .checked_add_signed(
107                        chrono::Duration::from_std(message.duration).expect("Invalid duration"),
108                    )
109                    .expect("Unexpected date math error");
110            if should_show {
111                return html! {
112                    <div class=format!("notification {}", message.kind.css_class())>
113                        { &message.content }
114                    </div>
115                };
116            }
117        }
118
119        Html::default()
120    }
121}