forked from alemi/upub
fix(web): only load tl after refresh
also improved tl.more()
This commit is contained in:
parent
eb3c647691
commit
6397647511
6 changed files with 50 additions and 96 deletions
|
@ -12,29 +12,6 @@ pub fn App() -> impl IntoView {
|
||||||
let (userid, set_userid) = use_cookie::<String, FromToStringCodec>("user_id");
|
let (userid, set_userid) = use_cookie::<String, FromToStringCodec>("user_id");
|
||||||
let (config, set_config, _) = use_local_storage::<crate::Config, JsonCodec>("config");
|
let (config, set_config, _) = use_local_storage::<crate::Config, JsonCodec>("config");
|
||||||
|
|
||||||
if let Some(tok) = token.get_untracked() {
|
|
||||||
spawn_local(async move {
|
|
||||||
match reqwest::Client::new()
|
|
||||||
.request(Method::PATCH, format!("{URL_BASE}/auth"))
|
|
||||||
.json(&serde_json::json!({"token": tok}))
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Err(e) => tracing::error!("could not refresh token: {e}"),
|
|
||||||
Ok(res) => match res.error_for_status() {
|
|
||||||
Err(e) => tracing::error!("server rejected refresh: {e}"),
|
|
||||||
Ok(doc) => match doc.json::<AuthResponse>().await {
|
|
||||||
Err(e) => tracing::error!("failed parsing auth response: {e}"),
|
|
||||||
Ok(auth) => {
|
|
||||||
set_token.set(Some(auth.token));
|
|
||||||
set_userid.set(Some(auth.user));
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let auth = Auth { token, userid };
|
let auth = Auth { token, userid };
|
||||||
provide_context(auth);
|
provide_context(auth);
|
||||||
provide_context(config);
|
provide_context(config);
|
||||||
|
@ -55,26 +32,39 @@ pub fn App() -> impl IntoView {
|
||||||
let (menu, set_menu) = create_signal(screen_width <= 786);
|
let (menu, set_menu) = create_signal(screen_width <= 786);
|
||||||
let (advanced, set_advanced) = create_signal(false);
|
let (advanced, set_advanced) = create_signal(false);
|
||||||
|
|
||||||
spawn_local(async move {
|
|
||||||
if let Err(e) = server_tl.more(auth).await {
|
|
||||||
tracing::error!("error populating timeline: {e}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let auth_present = auth.token.get_untracked().is_some(); // skip helper to use get_untracked
|
let auth_present = auth.token.get_untracked().is_some(); // skip helper to use get_untracked
|
||||||
if auth_present {
|
let title_target = move || if auth_present { "/web/home" } else { "/web/server" };
|
||||||
|
|
||||||
|
if let Some(tok) = token.get_untracked() {
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
if let Err(e) = home_tl.more(auth).await {
|
// refresh token first, or verify that we're still authed
|
||||||
tracing::error!("error populating timeline: {e}");
|
match reqwest::Client::new()
|
||||||
|
.request(Method::PATCH, format!("{URL_BASE}/auth"))
|
||||||
|
.json(&serde_json::json!({"token": tok}))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Err(e) => tracing::error!("could not refresh token: {e}"),
|
||||||
|
Ok(res) => match res.error_for_status() {
|
||||||
|
Err(e) => tracing::error!("server rejected refresh: {e}"),
|
||||||
|
Ok(doc) => match doc.json::<AuthResponse>().await {
|
||||||
|
Err(e) => tracing::error!("failed parsing auth response: {e}"),
|
||||||
|
Ok(auth) => {
|
||||||
|
set_token.set(Some(auth.token));
|
||||||
|
set_userid.set(Some(auth.user));
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let title_target = if auth_present { "/web/home" } else { "/web/server" };
|
server_tl.more(auth);
|
||||||
|
if auth_present { home_tl.more(auth) };
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<nav class="w-100 mt-1 mb-1 pb-s">
|
<nav class="w-100 mt-1 mb-1 pb-s">
|
||||||
<code class="color ml-3" ><a class="upub-title" href={title_target} >μpub</a></code>
|
<code class="color ml-3" ><a class="upub-title" href=title_target >μpub</a></code>
|
||||||
<small class="ml-1 mr-1 hidden-on-tiny" ><a class="clean" href="/web/server" >micro social network, federated</a></small>
|
<small class="ml-1 mr-1 hidden-on-tiny" ><a class="clean" href="/web/server" >micro social network, federated</a></small>
|
||||||
/* TODO kinda jank with the float but whatever, will do for now */
|
/* TODO kinda jank with the float but whatever, will do for now */
|
||||||
<input type="submit" class="mr-2 rev" on:click=move |_| set_menu.set(!menu.get()) value="menu" style="float: right" />
|
<input type="submit" class="mr-2 rev" on:click=move |_| set_menu.set(!menu.get()) value="menu" style="float: right" />
|
||||||
|
|
|
@ -19,11 +19,7 @@ pub fn LoginBox(
|
||||||
token_tx.set(None);
|
token_tx.set(None);
|
||||||
home_tl.reset(format!("{URL_BASE}/outbox/page"));
|
home_tl.reset(format!("{URL_BASE}/outbox/page"));
|
||||||
server_tl.reset(format!("{URL_BASE}/inbox/page"));
|
server_tl.reset(format!("{URL_BASE}/inbox/page"));
|
||||||
spawn_local(async move {
|
server_tl.more(auth);
|
||||||
if let Err(e) = server_tl.more(auth).await {
|
|
||||||
logging::error!("failed refreshing server timeline: {e}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} />
|
} />
|
||||||
</div>
|
</div>
|
||||||
<div class:hidden=move || auth.present() >
|
<div class:hidden=move || auth.present() >
|
||||||
|
@ -50,18 +46,10 @@ pub fn LoginBox(
|
||||||
token_tx.set(Some(auth_response.token));
|
token_tx.set(Some(auth_response.token));
|
||||||
// reset home feed and point it to our user's inbox
|
// reset home feed and point it to our user's inbox
|
||||||
home_tl.reset(format!("{URL_BASE}/users/{}/inbox/page", username));
|
home_tl.reset(format!("{URL_BASE}/users/{}/inbox/page", username));
|
||||||
spawn_local(async move {
|
home_tl.more(auth);
|
||||||
if let Err(e) = home_tl.more(auth).await {
|
|
||||||
tracing::error!("failed refreshing home timeline: {e}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// reset server feed: there may be more content now that we're authed
|
// reset server feed: there may be more content now that we're authed
|
||||||
server_tl.reset(format!("{URL_BASE}/inbox/page"));
|
server_tl.reset(format!("{URL_BASE}/inbox/page"));
|
||||||
spawn_local(async move {
|
server_tl.more(auth);
|
||||||
if let Err(e) = server_tl.more(auth).await {
|
|
||||||
tracing::error!("failed refreshing server timeline: {e}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
} >
|
} >
|
||||||
<table class="w-100 align">
|
<table class="w-100 align">
|
||||||
|
|
|
@ -36,14 +36,20 @@ impl Timeline {
|
||||||
self.over.set(false);
|
self.over.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn more(&self, auth: Auth) -> reqwest::Result<()> {
|
pub fn more(&self, auth: Auth) {
|
||||||
self.loading.set(true);
|
if self.loading.get() { return }
|
||||||
let res = self.more_inner(auth).await;
|
let _self = *self;
|
||||||
self.loading.set(false);
|
spawn_local(async move {
|
||||||
res
|
_self.loading.set(true);
|
||||||
|
let res = _self.load_more(auth).await;
|
||||||
|
_self.loading.set(false);
|
||||||
|
if let Err(e) = res {
|
||||||
|
tracing::error!("failed loading posts for timeline: {e}");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn more_inner(&self, auth: Auth) -> reqwest::Result<()> {
|
pub async fn load_more(&self, auth: Auth) -> reqwest::Result<()> {
|
||||||
use apb::{Collection, CollectionPage};
|
use apb::{Collection, CollectionPage};
|
||||||
|
|
||||||
let feed_url = self.next.get_untracked();
|
let feed_url = self.next.get_untracked();
|
||||||
|
@ -119,13 +125,7 @@ pub fn TimelineReplies(tl: Timeline, root: String) -> impl IntoView {
|
||||||
<div class="center mt-1 mb-1" class:hidden=tl.over >
|
<div class="center mt-1 mb-1" class:hidden=tl.over >
|
||||||
<button type="button"
|
<button type="button"
|
||||||
prop:disabled=tl.loading
|
prop:disabled=tl.loading
|
||||||
on:click=move |_| {
|
on:click=move |_| tl.more(auth)
|
||||||
spawn_local(async move {
|
|
||||||
if let Err(e) = tl.more(auth).await {
|
|
||||||
tracing::error!("error fetching more items for timeline: {e}");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{move || if tl.loading.get() {
|
{move || if tl.loading.get() {
|
||||||
view! { "loading"<span class="dots"></span> }.into_view()
|
view! { "loading"<span class="dots"></span> }.into_view()
|
||||||
|
@ -152,9 +152,7 @@ pub fn TimelineFeed(tl: Timeline) -> impl IntoView {
|
||||||
move |(s, h)| async move {
|
move |(s, h)| async move {
|
||||||
if !config.get().infinite_scroll { return }
|
if !config.get().infinite_scroll { return }
|
||||||
if s > 0.0 && h - s < view_height && !tl.loading.get() {
|
if s > 0.0 && h - s < view_height && !tl.loading.get() {
|
||||||
if let Err(e) = tl.more(auth).await {
|
tl.more(auth);
|
||||||
tracing::error!("auto load failed: {e}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -179,7 +177,7 @@ pub fn TimelineFeed(tl: Timeline) -> impl IntoView {
|
||||||
<div class="center mt-1 mb-1" class:hidden=tl.over >
|
<div class="center mt-1 mb-1" class:hidden=tl.over >
|
||||||
<button type="button"
|
<button type="button"
|
||||||
prop:disabled=tl.loading
|
prop:disabled=tl.loading
|
||||||
on:click=move |_| load_more(tl, auth)
|
on:click=move |_| tl.more(auth)
|
||||||
>
|
>
|
||||||
{move || if tl.loading.get() {
|
{move || if tl.loading.get() {
|
||||||
view! { "loading"<span class="dots"></span> }.into_view()
|
view! { "loading"<span class="dots"></span> }.into_view()
|
||||||
|
@ -189,16 +187,6 @@ pub fn TimelineFeed(tl: Timeline) -> impl IntoView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_more(tl: Timeline, auth: Auth) {
|
|
||||||
if !tl.loading.get() {
|
|
||||||
spawn_local(async move {
|
|
||||||
if let Err(e) = tl.more(auth).await {
|
|
||||||
tracing::error!("error fetching more items for timeline: {e}");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn process_activities(activities: Vec<serde_json::Value>, auth: Auth) -> Vec<String> {
|
async fn process_activities(activities: Vec<serde_json::Value>, auth: Auth) -> Vec<String> {
|
||||||
let mut sub_tasks : Vec<Pin<Box<dyn futures::Future<Output = ()>>>> = Vec::new();
|
let mut sub_tasks : Vec<Pin<Box<dyn futures::Future<Output = ()>>>> = Vec::new();
|
||||||
let mut gonna_fetch = BTreeSet::new();
|
let mut gonna_fetch = BTreeSet::new();
|
||||||
|
|
|
@ -41,11 +41,7 @@ pub fn ObjectPage(tl: Timeline) -> impl IntoView {
|
||||||
class:hidden=move || tl.is_empty()
|
class:hidden=move || tl.is_empty()
|
||||||
on:click=move |_| {
|
on:click=move |_| {
|
||||||
tl.reset(tl.next.get().split('?').next().unwrap_or_default().to_string());
|
tl.reset(tl.next.get().split('?').next().unwrap_or_default().to_string());
|
||||||
spawn_local(async move {
|
tl.more(auth);
|
||||||
if let Err(e) = tl.more(auth).await {
|
|
||||||
tracing::error!("error fetching more items for timeline: {e}");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}><span class="emoji">
|
}><span class="emoji">
|
||||||
"\u{1f5d8}"
|
"\u{1f5d8}"
|
||||||
</span></a>
|
</span></a>
|
||||||
|
|
|
@ -10,11 +10,7 @@ pub fn TimelinePage(name: &'static str, tl: Timeline) -> impl IntoView {
|
||||||
{name}
|
{name}
|
||||||
<a class="clean ml-1" href="#" on:click=move |_| {
|
<a class="clean ml-1" href="#" on:click=move |_| {
|
||||||
tl.reset(tl.next.get().split('?').next().unwrap_or_default().to_string());
|
tl.reset(tl.next.get().split('?').next().unwrap_or_default().to_string());
|
||||||
spawn_local(async move {
|
tl.more(auth);
|
||||||
if let Err(e) = tl.more(auth).await {
|
|
||||||
tracing::error!("error fetching more items for timeline: {e}");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}><span class="emoji">
|
}><span class="emoji">
|
||||||
"\u{1f5d8}"
|
"\u{1f5d8}"
|
||||||
</span></a>
|
</span></a>
|
||||||
|
|
|
@ -51,11 +51,7 @@ pub fn UserPage(tl: Timeline) -> impl IntoView {
|
||||||
class:hidden=move || tl.is_empty()
|
class:hidden=move || tl.is_empty()
|
||||||
on:click=move |_| {
|
on:click=move |_| {
|
||||||
tl.reset(tl.next.get().split('?').next().unwrap_or_default().to_string());
|
tl.reset(tl.next.get().split('?').next().unwrap_or_default().to_string());
|
||||||
spawn_local(async move {
|
tl.more(auth);
|
||||||
if let Err(e) = tl.more(auth).await {
|
|
||||||
tracing::error!("error fetching more items for timeline: {e}");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}><span class="emoji">
|
}><span class="emoji">
|
||||||
"\u{1f5d8}"
|
"\u{1f5d8}"
|
||||||
</span></a>
|
</span></a>
|
||||||
|
|
Loading…
Reference in a new issue