From d1b8d737cc4eaa64045e4c75eb4e9cc3d4a3e254 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Thu, 12 Oct 2023 23:11:20 +0800 Subject: [PATCH] Enable on-demand posting stats - Slight refactor - Make sure stats also work when switching instances - Make sure zero stats fallback --- src/components/account-info.css | 79 +++++++-- src/components/account-info.jsx | 275 +++++++++++++++++++------------- 2 files changed, 232 insertions(+), 122 deletions(-) diff --git a/src/components/account-info.css b/src/components/account-info.css index 930d1cf2..f3ab0414 100644 --- a/src/components/account-info.css +++ b/src/components/account-info.css @@ -342,23 +342,82 @@ opacity: 1; } } -.account-container .posting-stats { - font-size: 90%; - color: var(--text-insignificant-color); +.account-container .posting-stats-button { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + width: 100%; + color: inherit; background-color: var(--bg-faded-color); padding: 8px 12px; - --size: 8px; - --original-color: var(--link-color); + font-size: 90%; + color: var(--text-insignificant-color); + line-height: 1; + vertical-align: text-top; + border-radius: 4px; &:is(:hover, :focus-within) { + color: var(--text-color); background-color: var(--link-bg-hover-color); + filter: none !important; + } + + .loader-container { + margin: 0; + opacity: 0.5; + transform: scale(0.75); + } +} + +@keyframes wobble { + 0% { + transform: rotate(-4deg); + } + 100% { + transform: rotate(4deg); + } +} +@keyframes loading-spin { + 0% { + transform: rotate(0deg) scale(0.75); + } + 100% { + transform: rotate(360deg) scale(0.75); + } +} +.posting-stats-icon { + display: inline-block; + width: 24px; + height: 8px; + filter: opacity(0.75); + animation: wobble 2s linear both infinite alternate !important; + + &.loading { + animation: loading-spin 0.35s linear both infinite !important; + } +} + +.account-container { + --posting-stats-size: 8px; + --original-color: var(--link-color); + + .posting-stats { + font-size: 90%; + color: var(--text-insignificant-color); + background-color: var(--bg-faded-color); + padding: 8px 12px; + + &:is(:hover, :focus-within) { + background-color: var(--link-bg-hover-color); + } } .posting-stats-bar { --gap: 0.5px; --gap-color: var(--outline-color); - height: var(--size); - border-radius: var(--size); + height: var(--posting-stats-size); + border-radius: var(--posting-stats-size); overflow: hidden; margin: 8px 0; box-shadow: inset 0 0 0 1px var(--outline-color), @@ -388,9 +447,9 @@ .posting-stats-legend-item { display: inline-block; - width: var(--size); - height: var(--size); - border-radius: var(--size); + width: var(--posting-stats-size); + height: var(--posting-stats-size); + border-radius: var(--posting-stats-size); background-color: var(--text-insignificant-color); vertical-align: middle; margin: 0 4px 2px; diff --git a/src/components/account-info.jsx b/src/components/account-info.jsx index a49259d4..7ba339ef 100644 --- a/src/components/account-info.jsx +++ b/src/components/account-info.jsx @@ -206,71 +206,85 @@ function AccountInfo({ const [familiarFollowers, setFamiliarFollowers] = useState([]); const [postingStats, setPostingStats] = useState(); - const hasPostingStats = postingStats?.total >= 3; + const [postingStatsUIState, setPostingStatsUIState] = useState('default'); + const hasPostingStats = !!postingStats?.total; + const currentIDRef = useRef(); + + const renderFamiliarFollowers = async () => { + if (!currentIDRef.current) return; + const currentID = currentIDRef.current; + try { + const fetchFamiliarFollowers = + currentMasto.v1.accounts.familiarFollowers.fetch({ + id: [currentID], + }); + + const followers = await fetchFamiliarFollowers; + console.log('fetched familiar followers', followers); + setFamiliarFollowers( + followers[0].accounts.slice(0, FAMILIAR_FOLLOWERS_LIMIT), + ); + } catch (e) { + console.error(e); + } + }; + + const renderPostingStats = async () => { + setPostingStatsUIState('loading'); + try { + const fetchStatuses = masto.v1.accounts + .$select(id) + .statuses.list({ + limit: 20, + }) + .next(); + + const { value: statuses } = await fetchStatuses; + console.log('fetched statuses', statuses); + const stats = { + total: statuses.length, + originals: 0, + replies: 0, + boosts: 0, + }; + // Categories statuses by type + // - Original posts (not replies to others) + // - Threads (self-replies + 1st original post) + // - Boosts (reblogs) + // - Replies (not-self replies) + statuses.forEach((status) => { + if (status.reblog) { + stats.boosts++; + } else if (status.inReplyToAccountId !== id && !!status.inReplyToId) { + stats.replies++; + } else { + stats.originals++; + } + }); + + // Count days since last post + stats.daysSinceLastPost = Math.ceil( + (Date.now() - new Date(statuses[statuses.length - 1].createdAt)) / + 86400000, + ); + + console.log('posting stats', stats); + setPostingStats(stats); + setPostingStatsUIState('default'); + } catch (e) { + console.error(e); + setPostingStatsUIState('error'); + } + }; const onRelationshipChange = useCallback( ({ relationship, currentID }) => { + currentIDRef.current = currentID; if (!relationship.following) { - (async () => { - try { - const fetchFamiliarFollowers = - currentMasto.v1.accounts.familiarFollowers.fetch({ - id: [currentID], - }); - const fetchStatuses = currentMasto.v1.accounts - .$select(currentID) - .statuses.list({ - limit: 20, - }) - .next(); - - const followers = await fetchFamiliarFollowers; - console.log('fetched familiar followers', followers); - setFamiliarFollowers( - followers[0].accounts.slice(0, FAMILIAR_FOLLOWERS_LIMIT), - ); - - if (!standalone) { - const { value: statuses } = await fetchStatuses; - console.log('fetched statuses', statuses); - const stats = { - total: statuses.length, - originals: 0, - replies: 0, - boosts: 0, - }; - // Categories statuses by type - // - Original posts (not replies to others) - // - Threads (self-replies + 1st original post) - // - Boosts (reblogs) - // - Replies (not-self replies) - statuses.forEach((status) => { - if (status.reblog) { - stats.boosts++; - } else if ( - status.inReplyToAccountId !== currentID && - !!status.inReplyToId - ) { - stats.replies++; - } else { - stats.originals++; - } - }); - - // Count days since last post - stats.daysSinceLastPost = Math.ceil( - (Date.now() - - new Date(statuses[statuses.length - 1].createdAt)) / - 86400000, - ); - - console.log('posting stats', stats); - setPostingStats(stats); - } - } catch (e) { - console.error(e); - } - })(); + renderFamiliarFollowers(); + if (!standalone) { + renderPostingStats(); + } } }, [standalone], @@ -586,8 +600,8 @@ function AccountInfo({ )} - {hasPostingStats && ( - { @@ -596,60 +610,97 @@ function AccountInfo({ >
-
-
- {postingStats.daysSinceLastPost < 365 - ? `Last ${postingStats.total} posts in the past - ${postingStats.daysSinceLastPost} day${ - postingStats.daysSinceLastPost > 1 ? 's' : '' - }` - : ` - Last ${postingStats.total} posts in the past year(s) - `} -
+ {hasPostingStats ? (
-
- - {' '} - Original - {' '} - - {' '} - Replies - {' '} - - {' '} - Boosts - + class="posting-stats" + title={`${Math.round( + (postingStats.originals / postingStats.total) * 100, + )}% original posts, ${Math.round( + (postingStats.replies / postingStats.total) * 100, + )}% replies, ${Math.round( + (postingStats.boosts / postingStats.total) * 100, + )}% boosts`} + > +
+ {postingStats.daysSinceLastPost < 365 + ? `Last ${postingStats.total} posts in the past + ${postingStats.daysSinceLastPost} day${ + postingStats.daysSinceLastPost > 1 ? 's' : '' + }` + : ` + Last ${postingStats.total} posts in the past year(s) + `} +
+
+
+ + {' '} + Original + {' '} + + {' '} + Replies + {' '} + + {' '} + Boosts + +
-
+ ) : ( +
Post stats unavailable.
+ )}
- + )} +