webapp_frontend/component/
root.rs1use crate::{
4 api::Response,
5 component::{content::ContentComponent, login::LoginComponent},
6 route::RouterTarget,
7 service::{
8 cookie::CookieService,
9 uikit::{NotificationStatus, UIkitService},
10 },
11 string::{REQUEST_ERROR, RESPONSE_ERROR},
12 SESSION_COOKIE,
13};
14use log::{error, info, warn};
15use webapp::{
16 protocol::{model::Session, request::LoginSession, response::Login},
17 API_URL_LOGIN_SESSION,
18};
19use yew::{agent::Bridged, format::Cbor, html, prelude::*, services::fetch::FetchTask};
20use yew_router::{self, Route, RouterAgent};
21
22pub struct RootComponent {
24 child_component: RouterTarget,
25 cookie_service: CookieService,
26 fetch_task: Option<FetchTask>,
27 router_agent: Box<Bridge<RouterAgent<()>>>,
28 uikit_service: UIkitService,
29}
30
31pub enum Message {
33 Fetch(Response<Login>),
34 Route(Route<()>),
35}
36
37impl Component for RootComponent {
38 type Message = Message;
39 type Properties = ();
40
41 fn create(_: Self::Properties, mut link: ComponentLink<Self>) -> Self {
42 let cookie_service = CookieService::new();
44 let mut fetch_task = None;
45 let mut router_agent = RouterAgent::bridge(link.send_back(Message::Route));
46 let uikit_service = UIkitService::new();
47
48 if let Ok(token) = cookie_service.get(SESSION_COOKIE) {
50 fetch_task = fetch! {
51 LoginSession(Session::new(token)) => API_URL_LOGIN_SESSION,
52 link, Message::Fetch,
53 || {},
54 || {
55 error!("Unable to create session login request");
56 uikit_service.notify(REQUEST_ERROR, &NotificationStatus::Danger);
57 cookie_service.remove(SESSION_COOKIE);
58 router_agent.send(yew_router::Request::ChangeRoute(RouterTarget::Login.into()));
59 }
60 };
61 } else {
62 info!("No token found, routing to login");
63 router_agent.send(yew_router::Request::ChangeRoute(RouterTarget::Login.into()));
64 }
65
66 Self {
68 child_component: RouterTarget::Loading,
69 cookie_service,
70 fetch_task,
71 router_agent,
72 uikit_service,
73 }
74 }
75
76 fn change(&mut self, _: Self::Properties) -> ShouldRender {
77 true
78 }
79
80 fn update(&mut self, msg: Self::Message) -> ShouldRender {
81 match msg {
82 Message::Route(route) => self.child_component = route.into(),
84
85 Message::Fetch(response) => {
87 let (meta, Cbor(body)) = response.into_parts();
88
89 if meta.status.is_success() {
91 match body {
92 Ok(Login(Session { token })) => {
93 info!("Session based login succeed");
94
95 self.cookie_service.set(SESSION_COOKIE, &token);
97
98 self.router_agent.send(yew_router::Request::ChangeRoute(
100 RouterTarget::Content.into(),
101 ));
102 }
103 _ => {
104 warn!("Got wrong session login response");
106 self.uikit_service
107 .notify(RESPONSE_ERROR, &NotificationStatus::Danger);
108 self.router_agent
109 .send(yew_router::Request::ChangeRoute(RouterTarget::Login.into()));
110 }
111 }
112 } else {
113 warn!("Session login failed with status: {}", meta.status);
115 self.cookie_service.remove(SESSION_COOKIE);
116 self.router_agent
117 .send(yew_router::Request::ChangeRoute(RouterTarget::Login.into()));
118 }
119
120 self.fetch_task = None;
122 }
123 }
124 true
125 }
126}
127
128impl Renderable<RootComponent> for RootComponent {
129 fn view(&self) -> Html<Self> {
130 self.child_component.view()
131 }
132}
133
134impl Renderable<RootComponent> for RouterTarget {
135 fn view(&self) -> Html<RootComponent> {
136 match *self {
137 RouterTarget::Loading => {
138 html! {
139 <div class="uk-position-center", uk-icon="icon: cloud-download; ratio: 3",></div>
140 }
141 }
142 RouterTarget::Login => {
143 html! {
144 <LoginComponent:/>
145 }
146 }
147 RouterTarget::Content => {
148 html! {
149 <ContentComponent:/>
150 }
151 }
152 RouterTarget::Error => {
153 html! {
154 <div class="uk-position-center", uk-icon="icon: ban; ratio: 3",></div>
155 }
156 }
157 }
158 }
159}