Skip to content

Commit efafac0

Browse files
committed
Async load activity feed
1 parent 2aa856d commit efafac0

File tree

5 files changed

+82
-5
lines changed

5 files changed

+82
-5
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { buildPartialsUrl } from '../utils'
2+
3+
/**
4+
* Fetches and displays the activity feed for a "My Books" page.
5+
*
6+
* @param {HTMLElement} elem - Container for the activity feed
7+
* @returns {Promise<void>}
8+
*
9+
* @see `/openlibrary/templates/account/activity_feed.html` for activity feed template
10+
*/
11+
export async function initActivityFeedRequest(elem) {
12+
const fullPath = window.location.pathname
13+
const splitPath = fullPath.split('/')
14+
const username = splitPath[2] // Assumes an activity feed can only appear on the patron's "My Books" page
15+
16+
const loadingIndicator = elem.querySelector('.loadingIndicator')
17+
const retryElem = elem.querySelector('.activity-feed-retry')
18+
const retryButton = retryElem.querySelector('.retry-btn')
19+
20+
function fetchPartialsAndUpdatePage() {
21+
return fetch(buildPartialsUrl('ActivityFeed', {username: username}))
22+
.then(resp => {
23+
if (!resp.ok) {
24+
throw Error('Failed to fetch partials')
25+
}
26+
return resp.json()
27+
})
28+
.then(data => {
29+
const div = document.createElement('div')
30+
div.innerHTML = data.partials.trim()
31+
loadingIndicator.classList.add('hidden')
32+
retryButton.classList.add('hidden')
33+
for (const child of Array.from(div.children)) {
34+
elem.insertAdjacentElement('beforeend', child)
35+
}
36+
})
37+
.catch(() => {
38+
// Show retry affordance
39+
loadingIndicator.classList.add('hidden')
40+
retryElem.classList.remove('hidden')
41+
})
42+
}
43+
44+
// Hydrate retry button
45+
retryButton.addEventListener('click', async () => {
46+
retryElem.classList.add('hidden')
47+
loadingIndicator.classList.remove('hidden')
48+
await fetchPartialsAndUpdatePage()
49+
})
50+
51+
await fetchPartialsAndUpdatePage()
52+
}

openlibrary/plugins/openlibrary/js/index.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,4 +582,11 @@ jQuery(function () {
582582
import(/* webpackChunkName: "list-books" */ './list_books')
583583
.then(module => module.ListBooks.init());
584584
}
585+
586+
// Async-load activity feed
587+
const activityFeedContainer = document.querySelector('.activity-feed-container')
588+
if (activityFeedContainer) {
589+
import(/* webpackChunkName: "activity-feed" */ './activity-feed')
590+
.then(module => module.initActivityFeedRequest(activityFeedContainer))
591+
}
585592
});

openlibrary/plugins/openlibrary/partials.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from openlibrary.core.lending import compose_ia_url, get_available
1313
from openlibrary.i18n import gettext as _
1414
from openlibrary.plugins.openlibrary.lists import get_lists, get_user_lists
15+
from openlibrary.plugins.upstream.mybooks import ActivityFeed
1516
from openlibrary.plugins.upstream.yearly_reading_goals import get_reading_goals
1617
from openlibrary.plugins.worksearch.code import do_search, work_search
1718
from openlibrary.plugins.worksearch.subjects import (
@@ -354,6 +355,19 @@ def generate(self) -> dict:
354355
return {"partials": str(macro)}
355356

356357

358+
359+
class ActivityFeedPartial(PartialDataHandler):
360+
"""Handler for "My Books" page activity feeds"""
361+
def __init__(self):
362+
self.i = web.input(username=None)
363+
364+
def generate(self) -> dict:
365+
feed, follows_others = ActivityFeed.get_activity_feed(self.i.username)
366+
feed_url = f'/people/{self.i.username}/books/feed'
367+
template_result = render_template('account/activity_feed', feed, feed_url, follows_others)
368+
return {"partials": str(template_result)}
369+
370+
357371
class PartialRequestResolver:
358372
# Maps `_component` values to PartialDataHandler subclasses
359373
component_mapping = { # noqa: RUF012
@@ -365,6 +379,7 @@ class PartialRequestResolver:
365379
"LazyCarousel": LazyCarouselPartial,
366380
"MyBooksDropperLists": MyBooksDropperListsPartial,
367381
"ReadingGoalProgress": ReadingGoalProgressPartial,
382+
"ActivityFeed": ActivityFeedPartial,
368383
}
369384

370385
@staticmethod

openlibrary/templates/account/activity_feed.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
$def with(username)
1+
$def with(feed, feed_url, follows_others)
22

33
$# Renders the given feed in a container filled with cards.
44
$#
5-
$# * username (string) -- Username of a patron
5+
$# * feed (list) -- List of recent bookshelf events
6+
$# * feed_url (string) -- `href` for the feed's source
7+
$# * follows_others (boolean) -- `True` if the authenticated patron follows at least one person
68

79
$code:
8-
feed_url = '/people/%s/books/feed' % username
9-
feed, follows_others = get_activity_feed(username)
1010
shelf_id_to_name = {
1111
1: _('Want to Read'),
1212
2: _('Currently Reading'),

openlibrary/templates/account/mybooks.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ <h2 class="home-h2">
5050
<a href="$feed_url">$_("My Feed")</a>
5151
</h2>
5252
</div>
53-
$:render_template('account/activity_feed', username)
53+
$:macros.LoadingIndicator(_("Loading activity feed"), hidden=False)
54+
<div class="activity-feed-retry hidden">
55+
$_("Failed to fetch activity feed.") <a href="#" class="retry-btn">$_("Retry?")</a>
56+
</div>
5457
</div>
5558
$if owners_page or public:
5659
$:(compact_carousel(currently_reading) or empty_carousel(currently_reading))

0 commit comments

Comments
 (0)