diff --git a/devblog/devblog/client/src/api.rs b/devblog/devblog/client/src/api.rs index 4e54433..a273891 100644 --- a/devblog/devblog/client/src/api.rs +++ b/devblog/devblog/client/src/api.rs @@ -17,6 +17,7 @@ pub enum Api { EditPost(u32), GetPage(u32), GetPagesCount, + GetPageNumber(u32), GetPost(i32), GetPostsCount, GetCurrentUser, @@ -74,8 +75,9 @@ impl Api { } Api::EditComment(id) => format!("{}comments/{}", URL, id), Api::EditPost(id) => format!("{}posts/{}", URL, id), - Api::GetPage(num) => format!("{}posts/?page={}", URL, num), + Api::GetPage(num) => format!("{}posts?page={}", URL, num), Api::GetPagesCount => format!("{}posts/countPages", URL), + Api::GetPageNumber(id) => format!("{}posts/getPageNum/{}", URL, id), Api::GetPost(id) => format!("{}posts/{}", URL, id), Api::GetPostsCount => format!("{}posts/countPosts", URL), Api::GetCurrentUser => format!("{}accounts/user", URL), @@ -87,7 +89,7 @@ impl Api { Api::SignUp => format!("{}accounts/signup", URL), Api::ToggleSubscribe => format!("{}accounts/subscribe", URL), Api::UpdateVideoUrl => format!("{}YtVideo/1", URL), - Api::Vote(post_id, vote) => format!("{}posts/{}/{}", URL, post_id, vote), + Api::Vote(id, vote) => format!("{}posts/{}/{}", URL, id, vote), } } } diff --git a/devblog/devblog/client/src/components/notifications.rs b/devblog/devblog/client/src/components/notifications.rs index a01b78d..0cdc0e5 100644 --- a/devblog/devblog/client/src/components/notifications.rs +++ b/devblog/devblog/client/src/components/notifications.rs @@ -1,13 +1,15 @@ use crate::{ helpers::{self, CustomCallback}, icons::icons::BellIcon, + router::{PostQuery, Route}, store::Store, Api, Notification, }; use gloo_net::http::Method; +use std::{ops::Deref, rc::Rc}; use stylist::Style; use yew::prelude::*; -use yew_router::hooks::use_location; +use yew_router::hooks::use_navigator; use yewdux::use_store_value; const STYLE: &str = include_str!("styles/notifications.css"); @@ -28,7 +30,7 @@ pub fn notifications(props: &Props) -> Html { let notifications_cb = CustomCallback::new(¬ifications); let store = use_store_value::(); let onclick_bell = props.onclick_bell.clone(); - let location = use_location(); + let navigator = use_navigator(); // get all notifications for user let token = store.token.clone(); @@ -61,8 +63,61 @@ pub fn notifications(props: &Props) -> Html { use_effect_with(notifications.clone(), move |n| { display_clone.set(if n.len() > 0 { "inline" } else { "none" }.to_string()); }); - // let token = store.token.clone(); - // let username = store.username.clone(); + + let nav_to_post = |post_id: u32| -> Callback { + let navigator = navigator.clone(); + Callback::from(move |_| { + let navigator = navigator.clone().unwrap(); + wasm_bindgen_futures::spawn_local(async move { + let response = Api::GetPageNumber(post_id) + .fetch(None, None, Method::GET) + .await; + + if let Some(res) = response { + if res.status() == 200 { + let data = res.text().await.unwrap(); + let page_num = serde_json::from_str::(&data).unwrap(); + + let query = &PostQuery { page: page_num }; + let _ = navigator.push_with_query(&Route::Posts, &query); + } + } + }); + }) + }; + + let delete_notification = |post_id: u32, + store: Rc, + notifications: UseStateHandle>| + -> Callback { + let store_clone = store.clone(); + let notifications = notifications.clone(); + + Callback::from(move |_| { + let hdrs = helpers::create_auth_header(&store_clone.token); + let username = store_clone.username.clone(); + let notifications = notifications.clone(); + + wasm_bindgen_futures::spawn_local(async move { + let response = Api::DeleteNotification(post_id, username) + .fetch(Some(hdrs), None, Method::DELETE) + .await; + + if let Some(res) = response { + // if delete is success, remove the deleted notifications from the notifications vec + if res.status() == 200 { + let mut new_notifications = notifications.deref().clone(); + if let Some(idx) = + new_notifications.iter().position(|n| n.post_id == post_id) + { + new_notifications.remove(idx); + notifications.set(new_notifications); + } + } + } + }); + }) + }; html! { if store.authenticated { @@ -79,34 +134,22 @@ pub fn notifications(props: &Props) -> Html {
if !*loading && props.is_bell_clicked && !props.is_menu_clicked { {for notifications.iter().enumerate().map(|(_idx, n)| { + let id = n.post_id; + + html! { +
+ // thumbnail + + post thumbnail + - let store_clone = store.clone(); - let id = n.post_id; - let delete_notification = { - Callback::from(move |_| { - let hdrs = helpers::create_auth_header(&store_clone.token); - let username = store_clone.username.clone(); - - wasm_bindgen_futures::spawn_local(async move { - let response = Api::DeleteNotification(id, username) - .fetch(Some(hdrs), None, Method::DELETE) - .await; - }); - }) - }; - - html! { -
- // thumbnail - - post thumbnail - -
- {n.username.clone()}{" posted"} - {" dismiss"} +
+ {n.username.clone()}{" posted"} + {" dismiss"} +
-
- }})} + } + })} }
diff --git a/devblog/devblog/client/src/components/post_edit.rs b/devblog/devblog/client/src/components/post_edit.rs index 107bdbf..060f654 100644 --- a/devblog/devblog/client/src/components/post_edit.rs +++ b/devblog/devblog/client/src/components/post_edit.rs @@ -34,7 +34,7 @@ pub fn edit_post(props: &Props) -> Html { Callback::from(move |e: SubmitEvent| { e.prevent_default(); let description = description.clone(); - let body = Some(helpers::to_jsvalue(description.deref().clone())); + let body = Some(helpers::to_jsvalue(description.deref())); let hdrs = helpers::create_auth_header(&token); hdrs.append("content-type", "application/json"); let on_post_edit = on_post_edit.clone(); diff --git a/devblog/devblog/client/src/models.rs b/devblog/devblog/client/src/models.rs index 5a0a09c..fe249df 100644 --- a/devblog/devblog/client/src/models.rs +++ b/devblog/devblog/client/src/models.rs @@ -72,7 +72,7 @@ pub struct VoteCount { pub down: usize, } -#[derive(Serialize, Deserialize, Default, PartialEq)] +#[derive(Serialize, Deserialize, Default, PartialEq, Clone)] pub struct Notification { #[serde(rename = "imgUrl")] pub img_url: String, diff --git a/devblog/devblog/client/src/pages/posts.rs b/devblog/devblog/client/src/pages/posts.rs index 8366e24..818c15d 100644 --- a/devblog/devblog/client/src/pages/posts.rs +++ b/devblog/devblog/client/src/pages/posts.rs @@ -1,14 +1,17 @@ use crate::{ components::{pager::Pager, post::Post}, helpers::{self, CustomCallback}, - router::Route, + router::{PostQuery, Route}, store::Store, Api, PostModel, }; use gloo_net::http::Method; use stylist::Style; use yew::prelude::*; -use yew_router::components::Link; +use yew_router::{ + components::Link, + hooks::{use_location, use_navigator}, +}; use yewdux::use_store_value; const STYLE: &str = include_str!("styles/posts.css"); @@ -26,6 +29,8 @@ pub fn posts() -> Html { let posts_cb = CustomCallback::new(&posts); let posts_count_cb = CustomCallback::new(&posts_count); let pages_count_cb = CustomCallback::new(&pages_count); + let location = use_location(); + let navigator = use_navigator(); // get pages count and posts count let get_count = |posts_ct_cb: Callback, pages_ct_cb: Callback| { @@ -47,10 +52,18 @@ pub fn posts() -> Html { // get posts for current page let page_num_clone = page_num.clone(); let loading_clone = loading.clone(); - use_effect_with(trigger.clone(), move |_| { + let location = location.clone(); + use_effect_with(page_num_clone.clone(), move |_| { wasm_bindgen_futures::spawn_local(async move { loading_clone.set(true); - let num = *page_num_clone as u32; + let mut num = *page_num_clone as u32; + + let query = location.unwrap().query::(); + if let Ok(q) = query { + num = q.page; + } + + page_num_clone.set(num as i32); let res = Api::GetPage(num).fetch(None, None, Method::GET).await; helpers::emit(&posts_cb, res.unwrap()).await; loading_clone.set(false); @@ -60,9 +73,12 @@ pub fn posts() -> Html { // page left / right callback let trigger_clone = trigger.clone(); let on_pager_click = { + let navigator = navigator.clone().unwrap(); let page_num = page_num.clone(); Callback::from(move |page: i32| { trigger_clone.set(!*trigger_clone); + let query = &PostQuery { page: page as u32 }; + let _ = navigator.push_with_query(&Route::Posts, &query); page_num.set(page) }) }; diff --git a/devblog/devblog/client/src/router.rs b/devblog/devblog/client/src/router.rs index d1ec2d1..25f93a9 100644 --- a/devblog/devblog/client/src/router.rs +++ b/devblog/devblog/client/src/router.rs @@ -1,3 +1,4 @@ +use serde::{Deserialize, Serialize}; use yew::{html, Html}; use yew_router::Routable; @@ -41,3 +42,8 @@ pub fn switch(routes: Route) -> Html { Route::SignOut => html! {}, } } + +#[derive(Serialize, Deserialize)] +pub struct PostQuery { + pub page: u32, +} diff --git a/devblog/devblog/client/src/store.rs b/devblog/devblog/client/src/store.rs index 87943f2..fd39e66 100644 --- a/devblog/devblog/client/src/store.rs +++ b/devblog/devblog/client/src/store.rs @@ -4,10 +4,21 @@ use yewdux::prelude::*; #[derive(Clone, Serialize, Deserialize, Store, PartialEq, Debug, Default)] #[store(storage = "local")] pub struct Store { - pub username: String, - pub token: String, - pub expiration: String, #[serde(default)] pub authenticated: bool, pub admin: bool, + pub expiration: String, + pub token: String, + pub username: String, + #[serde(default)] + pub page_num: i32, +} + +#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)] +pub struct PageNum(u32); + +impl Default for PageNum { + fn default() -> Self { + PageNum(1) + } }