1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use yew::prelude::*;
use embedded_svc::utils::role::Role;
use crate::field::Field;
use crate::loading::*;
use crate::util::if_true;
#[derive(Properties, Clone, Default, Debug, PartialEq)]
pub struct AuthProps {
#[prop_or_default]
pub username: String,
#[prop_or_default]
pub password: String,
#[prop_or_default]
pub auth_failed: bool,
#[prop_or_default]
pub authenticating: bool,
pub submit: Callback<(String, String)>,
}
#[function_component(Auth)]
pub fn auth(props: &AuthProps) -> Html {
let mut username = Field::text(Ok);
let mut password = Field::text(Ok);
username.update(props.username.clone());
password.update(props.password.clone());
let disabled = props.authenticating;
let hidden = if_true(
!props.auth_failed || props.authenticating,
"visibility: hidden;",
);
let onclick = {
let username = username.clone();
let password = password.clone();
let submit = props.submit.clone();
Callback::from(move |_| {
submit.emit((
username.value().unwrap_or_default(),
password.value().unwrap_or_default(),
))
})
};
html! {
<div class="box has-text-centered">
<div class="field">
<label class="label">{"Username"}</label>
<div class="control">
<input
class="input"
type="text"
placeholder="0..24 characters"
value={username.raw_value()}
oninput={username.change()}
{disabled}
/>
</div>
</div>
<div class="field">
<label class="label">{"Password"}</label>
<div class="control">
<input
class="input"
type="password"
placeholder="0..24 characters"
value={password.raw_value()}
oninput={password.change()}
{disabled}
/>
</div>
</div>
<p class="help is-danger" style={hidden}>{"Invalid username or password"}</p>
<button
class={classes!("button", "my-4", if_true(props.authenticating, "is-loading"))}
{disabled}
{onclick}
>
{"Login"}
</button>
</div>
}
}
#[derive(Properties, Clone, Default, Debug, PartialEq)]
pub struct AuthStateProps {
pub role: Option<Role>,
}
#[function_component(AuthState)]
pub fn auth_state(props: &AuthStateProps) -> Html {
match props.role {
Some(Role::None) => {
html! {
<div class="box has-text-centered">{"You are logged out."}</div>
}
}
None => {
html! {
<Loading/>
}
}
Some(role) => {
html! {
<div class="box has-text-centered">{format!("You are logged in as {}.", role)}</div>
}
}
}
}
#[function_component(NoPerm)]
pub fn no_perm() -> Html {
html! {
<div class="box has-text-centered">
{"You have no permissions to access this content"}
</div>
}
}