Skip to content

Commit 7a5cf8d

Browse files
committed
fix notification system
1 parent 835478f commit 7a5cf8d

File tree

7 files changed

+119
-41
lines changed

7 files changed

+119
-41
lines changed

devblog/devblog/client/src/api.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub enum Api {
1717
EditPost(u32),
1818
GetPage(u32),
1919
GetPagesCount,
20+
GetPageNumber(u32),
2021
GetPost(i32),
2122
GetPostsCount,
2223
GetCurrentUser,
@@ -74,8 +75,9 @@ impl Api {
7475
}
7576
Api::EditComment(id) => format!("{}comments/{}", URL, id),
7677
Api::EditPost(id) => format!("{}posts/{}", URL, id),
77-
Api::GetPage(num) => format!("{}posts/?page={}", URL, num),
78+
Api::GetPage(num) => format!("{}posts?page={}", URL, num),
7879
Api::GetPagesCount => format!("{}posts/countPages", URL),
80+
Api::GetPageNumber(id) => format!("{}posts/getPageNum/{}", URL, id),
7981
Api::GetPost(id) => format!("{}posts/{}", URL, id),
8082
Api::GetPostsCount => format!("{}posts/countPosts", URL),
8183
Api::GetCurrentUser => format!("{}accounts/user", URL),
@@ -87,7 +89,7 @@ impl Api {
8789
Api::SignUp => format!("{}accounts/signup", URL),
8890
Api::ToggleSubscribe => format!("{}accounts/subscribe", URL),
8991
Api::UpdateVideoUrl => format!("{}YtVideo/1", URL),
90-
Api::Vote(post_id, vote) => format!("{}posts/{}/{}", URL, post_id, vote),
92+
Api::Vote(id, vote) => format!("{}posts/{}/{}", URL, id, vote),
9193
}
9294
}
9395
}

devblog/devblog/client/src/components/notifications.rs

Lines changed: 73 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
use crate::{
22
helpers::{self, CustomCallback},
33
icons::icons::BellIcon,
4+
router::{PostQuery, Route},
45
store::Store,
56
Api, Notification,
67
};
78
use gloo_net::http::Method;
9+
use std::{ops::Deref, rc::Rc};
810
use stylist::Style;
911
use yew::prelude::*;
10-
use yew_router::hooks::use_location;
12+
use yew_router::hooks::use_navigator;
1113
use yewdux::use_store_value;
1214

1315
const STYLE: &str = include_str!("styles/notifications.css");
@@ -28,7 +30,7 @@ pub fn notifications(props: &Props) -> Html {
2830
let notifications_cb = CustomCallback::new(&notifications);
2931
let store = use_store_value::<Store>();
3032
let onclick_bell = props.onclick_bell.clone();
31-
let location = use_location();
33+
let navigator = use_navigator();
3234

3335
// get all notifications for user
3436
let token = store.token.clone();
@@ -61,8 +63,61 @@ pub fn notifications(props: &Props) -> Html {
6163
use_effect_with(notifications.clone(), move |n| {
6264
display_clone.set(if n.len() > 0 { "inline" } else { "none" }.to_string());
6365
});
64-
// let token = store.token.clone();
65-
// let username = store.username.clone();
66+
67+
let nav_to_post = |post_id: u32| -> Callback<MouseEvent> {
68+
let navigator = navigator.clone();
69+
Callback::from(move |_| {
70+
let navigator = navigator.clone().unwrap();
71+
wasm_bindgen_futures::spawn_local(async move {
72+
let response = Api::GetPageNumber(post_id)
73+
.fetch(None, None, Method::GET)
74+
.await;
75+
76+
if let Some(res) = response {
77+
if res.status() == 200 {
78+
let data = res.text().await.unwrap();
79+
let page_num = serde_json::from_str::<u32>(&data).unwrap();
80+
81+
let query = &PostQuery { page: page_num };
82+
let _ = navigator.push_with_query(&Route::Posts, &query);
83+
}
84+
}
85+
});
86+
})
87+
};
88+
89+
let delete_notification = |post_id: u32,
90+
store: Rc<Store>,
91+
notifications: UseStateHandle<Vec<Notification>>|
92+
-> Callback<MouseEvent> {
93+
let store_clone = store.clone();
94+
let notifications = notifications.clone();
95+
96+
Callback::from(move |_| {
97+
let hdrs = helpers::create_auth_header(&store_clone.token);
98+
let username = store_clone.username.clone();
99+
let notifications = notifications.clone();
100+
101+
wasm_bindgen_futures::spawn_local(async move {
102+
let response = Api::DeleteNotification(post_id, username)
103+
.fetch(Some(hdrs), None, Method::DELETE)
104+
.await;
105+
106+
if let Some(res) = response {
107+
// if delete is success, remove the deleted notifications from the notifications vec
108+
if res.status() == 200 {
109+
let mut new_notifications = notifications.deref().clone();
110+
if let Some(idx) =
111+
new_notifications.iter().position(|n| n.post_id == post_id)
112+
{
113+
new_notifications.remove(idx);
114+
notifications.set(new_notifications);
115+
}
116+
}
117+
}
118+
});
119+
})
120+
};
66121

67122
html! {
68123
if store.authenticated {
@@ -79,34 +134,22 @@ pub fn notifications(props: &Props) -> Html {
79134
<div class="notifications">
80135
if !*loading && props.is_bell_clicked && !props.is_menu_clicked {
81136
{for notifications.iter().enumerate().map(|(_idx, n)| {
137+
let id = n.post_id;
138+
139+
html! {
140+
<div class="">
141+
// thumbnail
142+
<span>
143+
<img src={n.img_url.clone()} alt="post thumbnail"/>
144+
</span>
82145

83-
let store_clone = store.clone();
84-
let id = n.post_id;
85-
let delete_notification = {
86-
Callback::from(move |_| {
87-
let hdrs = helpers::create_auth_header(&store_clone.token);
88-
let username = store_clone.username.clone();
89-
90-
wasm_bindgen_futures::spawn_local(async move {
91-
let response = Api::DeleteNotification(id, username)
92-
.fetch(Some(hdrs), None, Method::DELETE)
93-
.await;
94-
});
95-
})
96-
};
97-
98-
html! {
99-
<div class="">
100-
// thumbnail
101-
<span>
102-
<img src={n.img_url.clone()} alt="post thumbnail"/>
103-
</span>
104-
<div class="notification-txt">
105-
<span>{n.username.clone()}{" posted"}</span>
106-
<span onclick={delete_notification}>{" dismiss"}</span>
146+
<div class="notification-txt">
147+
<span onclick={nav_to_post(id)}>{n.username.clone()}{" posted"}</span>
148+
<span onclick={delete_notification(id, store.clone(), notifications.clone())}>{" dismiss"}</span>
149+
</div>
107150
</div>
108-
</div>
109-
}})}
151+
}
152+
})}
110153
}
111154
</div>
112155
</div>

devblog/devblog/client/src/components/post_edit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn edit_post(props: &Props) -> Html {
3434
Callback::from(move |e: SubmitEvent| {
3535
e.prevent_default();
3636
let description = description.clone();
37-
let body = Some(helpers::to_jsvalue(description.deref().clone()));
37+
let body = Some(helpers::to_jsvalue(description.deref()));
3838
let hdrs = helpers::create_auth_header(&token);
3939
hdrs.append("content-type", "application/json");
4040
let on_post_edit = on_post_edit.clone();

devblog/devblog/client/src/models.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub struct VoteCount {
7272
pub down: usize,
7373
}
7474

75-
#[derive(Serialize, Deserialize, Default, PartialEq)]
75+
#[derive(Serialize, Deserialize, Default, PartialEq, Clone)]
7676
pub struct Notification {
7777
#[serde(rename = "imgUrl")]
7878
pub img_url: String,

devblog/devblog/client/src/pages/posts.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
use crate::{
22
components::{pager::Pager, post::Post},
33
helpers::{self, CustomCallback},
4-
router::Route,
4+
router::{PostQuery, Route},
55
store::Store,
66
Api, PostModel,
77
};
88
use gloo_net::http::Method;
99
use stylist::Style;
1010
use yew::prelude::*;
11-
use yew_router::components::Link;
11+
use yew_router::{
12+
components::Link,
13+
hooks::{use_location, use_navigator},
14+
};
1215
use yewdux::use_store_value;
1316

1417
const STYLE: &str = include_str!("styles/posts.css");
@@ -26,6 +29,8 @@ pub fn posts() -> Html {
2629
let posts_cb = CustomCallback::new(&posts);
2730
let posts_count_cb = CustomCallback::new(&posts_count);
2831
let pages_count_cb = CustomCallback::new(&pages_count);
32+
let location = use_location();
33+
let navigator = use_navigator();
2934

3035
// get pages count and posts count
3136
let get_count = |posts_ct_cb: Callback<i32>, pages_ct_cb: Callback<i32>| {
@@ -47,10 +52,18 @@ pub fn posts() -> Html {
4752
// get posts for current page
4853
let page_num_clone = page_num.clone();
4954
let loading_clone = loading.clone();
50-
use_effect_with(trigger.clone(), move |_| {
55+
let location = location.clone();
56+
use_effect_with(page_num_clone.clone(), move |_| {
5157
wasm_bindgen_futures::spawn_local(async move {
5258
loading_clone.set(true);
53-
let num = *page_num_clone as u32;
59+
let mut num = *page_num_clone as u32;
60+
61+
let query = location.unwrap().query::<PostQuery>();
62+
if let Ok(q) = query {
63+
num = q.page;
64+
}
65+
66+
page_num_clone.set(num as i32);
5467
let res = Api::GetPage(num).fetch(None, None, Method::GET).await;
5568
helpers::emit(&posts_cb, res.unwrap()).await;
5669
loading_clone.set(false);
@@ -60,9 +73,12 @@ pub fn posts() -> Html {
6073
// page left / right callback
6174
let trigger_clone = trigger.clone();
6275
let on_pager_click = {
76+
let navigator = navigator.clone().unwrap();
6377
let page_num = page_num.clone();
6478
Callback::from(move |page: i32| {
6579
trigger_clone.set(!*trigger_clone);
80+
let query = &PostQuery { page: page as u32 };
81+
let _ = navigator.push_with_query(&Route::Posts, &query);
6682
page_num.set(page)
6783
})
6884
};

devblog/devblog/client/src/router.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use serde::{Deserialize, Serialize};
12
use yew::{html, Html};
23
use yew_router::Routable;
34

@@ -41,3 +42,8 @@ pub fn switch(routes: Route) -> Html {
4142
Route::SignOut => html! {<SignOut />},
4243
}
4344
}
45+
46+
#[derive(Serialize, Deserialize)]
47+
pub struct PostQuery {
48+
pub page: u32,
49+
}

devblog/devblog/client/src/store.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,21 @@ use yewdux::prelude::*;
44
#[derive(Clone, Serialize, Deserialize, Store, PartialEq, Debug, Default)]
55
#[store(storage = "local")]
66
pub struct Store {
7-
pub username: String,
8-
pub token: String,
9-
pub expiration: String,
107
#[serde(default)]
118
pub authenticated: bool,
129
pub admin: bool,
10+
pub expiration: String,
11+
pub token: String,
12+
pub username: String,
13+
#[serde(default)]
14+
pub page_num: i32,
15+
}
16+
17+
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
18+
pub struct PageNum(u32);
19+
20+
impl Default for PageNum {
21+
fn default() -> Self {
22+
PageNum(1)
23+
}
1324
}

0 commit comments

Comments
 (0)