this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix familiar followers leaked to other profiles

Mistake for using global state when it should be per-profile

+159 -146
+159 -146
src/components/account-info.jsx
··· 1 1 import './account-info.css'; 2 2 3 3 import { Menu, MenuDivider, MenuItem, SubMenu } from '@szhsin/react-menu'; 4 - import { useEffect, useMemo, useReducer, useRef, useState } from 'preact/hooks'; 5 - import { proxy, useSnapshot } from 'valtio'; 4 + import { 5 + useCallback, 6 + useEffect, 7 + useMemo, 8 + useReducer, 9 + useRef, 10 + useState, 11 + } from 'preact/hooks'; 6 12 7 13 import { api } from '../utils/api'; 8 14 import enhanceContent from '../utils/enhance-content'; ··· 49 55 50 56 const LIMIT = 80; 51 57 52 - const accountInfoStates = proxy({ 53 - familiarFollowers: [], 54 - }); 55 - 56 58 function AccountInfo({ 57 59 account, 58 60 fetchAccount = () => {}, ··· 63 65 const { masto } = api({ 64 66 instance, 65 67 }); 68 + const { masto: currentMasto } = api(); 66 69 const [uiState, setUIState] = useState('default'); 67 70 const isString = typeof account === 'string'; 68 71 const [info, setInfo] = useState(isString ? null : account); 69 - const snapAccountInfoStates = useSnapshot(accountInfoStates); 70 72 71 73 const isSelf = useMemo( 72 74 () => account.id === store.session.get('currentAccount'), ··· 202 204 const LinkOrDiv = standalone ? 'div' : Link; 203 205 const accountLink = instance ? `/${instance}/a/${id}` : `/a/${id}`; 204 206 207 + const [familiarFollowers, setFamiliarFollowers] = useState([]); 208 + const [postingStats, setPostingStats] = useState(); 209 + const hasPostingStats = postingStats?.total >= 3; 210 + 211 + const onRelationshipChange = useCallback( 212 + ({ relationship, currentID }) => { 213 + if (!relationship.following) { 214 + (async () => { 215 + try { 216 + const fetchFamiliarFollowers = 217 + currentMasto.v1.accounts.fetchFamiliarFollowers(currentID); 218 + const fetchStatuses = currentMasto.v1.accounts 219 + .listStatuses(currentID, { 220 + limit: 20, 221 + }) 222 + .next(); 223 + 224 + const followers = await fetchFamiliarFollowers; 225 + console.log('fetched familiar followers', followers); 226 + setFamiliarFollowers( 227 + followers[0].accounts.slice(0, FAMILIAR_FOLLOWERS_LIMIT), 228 + ); 229 + 230 + if (!standalone) { 231 + const { value: statuses } = await fetchStatuses; 232 + console.log('fetched statuses', statuses); 233 + const stats = { 234 + total: statuses.length, 235 + originals: 0, 236 + replies: 0, 237 + boosts: 0, 238 + }; 239 + // Categories statuses by type 240 + // - Original posts (not replies to others) 241 + // - Threads (self-replies + 1st original post) 242 + // - Boosts (reblogs) 243 + // - Replies (not-self replies) 244 + statuses.forEach((status) => { 245 + if (status.reblog) { 246 + stats.boosts++; 247 + } else if ( 248 + status.inReplyToAccountId !== currentID && 249 + !!status.inReplyToId 250 + ) { 251 + stats.replies++; 252 + } else { 253 + stats.originals++; 254 + } 255 + }); 256 + 257 + // Count days since last post 258 + stats.daysSinceLastPost = Math.ceil( 259 + (Date.now() - 260 + new Date(statuses[statuses.length - 1].createdAt)) / 261 + 86400000, 262 + ); 263 + 264 + console.log('posting stats', stats); 265 + setPostingStats(stats); 266 + } 267 + } catch (e) { 268 + console.error(e); 269 + } 270 + })(); 271 + } 272 + }, 273 + [standalone], 274 + ); 275 + 205 276 return ( 206 277 <div 207 278 class={`account-container ${uiState === 'loading' ? 'skeleton' : ''}`} ··· 447 518 }; 448 519 }} 449 520 > 450 - {!!snapAccountInfoStates.familiarFollowers.length && ( 521 + {!!familiarFollowers.length && ( 451 522 <span class="shazam-container-horizontal"> 452 523 <span class="shazam-container-inner stats-avatars-bunch"> 453 - {(snapAccountInfoStates.familiarFollowers || []).map( 454 - (follower) => ( 455 - <Avatar 456 - url={follower.avatarStatic} 457 - size="s" 458 - alt={`${follower.displayName} @${follower.acct}`} 459 - squircle={follower?.bot} 460 - /> 461 - ), 462 - )} 524 + {familiarFollowers.map((follower) => ( 525 + <Avatar 526 + url={follower.avatarStatic} 527 + size="s" 528 + alt={`${follower.displayName} @${follower.acct}`} 529 + squircle={follower?.bot} 530 + /> 531 + ))} 463 532 </span> 464 533 </span> 465 534 )} ··· 514 583 )} 515 584 </div> 516 585 </div> 586 + {hasPostingStats && ( 587 + <Link 588 + to={accountLink} 589 + class="account-metadata-box" 590 + onClick={() => { 591 + states.showAccount = false; 592 + }} 593 + > 594 + <div class="shazam-container"> 595 + <div class="shazam-container-inner"> 596 + <div 597 + class="posting-stats" 598 + title={`${Math.round( 599 + (postingStats.originals / postingStats.total) * 100, 600 + )}% original posts, ${Math.round( 601 + (postingStats.replies / postingStats.total) * 100, 602 + )}% replies, ${Math.round( 603 + (postingStats.boosts / postingStats.total) * 100, 604 + )}% boosts`} 605 + > 606 + <div> 607 + {postingStats.daysSinceLastPost < 365 608 + ? `Last ${postingStats.total} posts in the past 609 + ${postingStats.daysSinceLastPost} day${ 610 + postingStats.daysSinceLastPost > 1 ? 's' : '' 611 + }` 612 + : ` 613 + Last ${postingStats.total} posts in the past year(s) 614 + `} 615 + </div> 616 + <div 617 + class="posting-stats-bar" 618 + style={{ 619 + // [originals | replies | boosts] 620 + '--originals-percentage': `${ 621 + (postingStats.originals / postingStats.total) * 622 + 100 623 + }%`, 624 + '--replies-percentage': `${ 625 + ((postingStats.originals + postingStats.replies) / 626 + postingStats.total) * 627 + 100 628 + }%`, 629 + }} 630 + /> 631 + <div class="posting-stats-legends"> 632 + <span class="ib"> 633 + <span class="posting-stats-legend-item posting-stats-legend-item-originals" />{' '} 634 + Original 635 + </span>{' '} 636 + <span class="ib"> 637 + <span class="posting-stats-legend-item posting-stats-legend-item-replies" />{' '} 638 + Replies 639 + </span>{' '} 640 + <span class="ib"> 641 + <span class="posting-stats-legend-item posting-stats-legend-item-boosts" />{' '} 642 + Boosts 643 + </span> 644 + </div> 645 + </div> 646 + </div> 647 + </div> 648 + </Link> 649 + )} 517 650 <RelatedActions 518 651 info={info} 519 652 instance={instance} 520 653 authenticated={authenticated} 521 - standalone={standalone} 654 + onRelationshipChange={onRelationshipChange} 522 655 /> 523 656 </main> 524 657 </> ··· 530 663 531 664 const FAMILIAR_FOLLOWERS_LIMIT = 3; 532 665 533 - function RelatedActions({ info, instance, authenticated, standalone }) { 666 + function RelatedActions({ 667 + info, 668 + instance, 669 + authenticated, 670 + onRelationshipChange = () => {}, 671 + }) { 534 672 if (!info) return null; 535 673 const { 536 674 masto: currentMasto, ··· 541 679 542 680 const [relationshipUIState, setRelationshipUIState] = useState('default'); 543 681 const [relationship, setRelationship] = useState(null); 544 - const [postingStats, setPostingStats] = useState(); 545 682 546 683 const { id, acct, url, username, locked, lastStatusAt, note, fields, moved } = 547 684 info; ··· 604 741 if (moved) return; 605 742 606 743 setRelationshipUIState('loading'); 607 - accountInfoStates.familiarFollowers = []; 608 - setPostingStats(null); 609 744 610 745 const fetchRelationships = currentMasto.v1.accounts.fetchRelationships([ 611 746 currentID, ··· 619 754 if (relationships.length) { 620 755 const relationship = relationships[0]; 621 756 setRelationship(relationship); 622 - 623 - if (!relationship.following) { 624 - try { 625 - const fetchFamiliarFollowers = 626 - currentMasto.v1.accounts.fetchFamiliarFollowers(currentID); 627 - const fetchStatuses = currentMasto.v1.accounts 628 - .listStatuses(currentID, { 629 - limit: 20, 630 - }) 631 - .next(); 632 - 633 - const followers = await fetchFamiliarFollowers; 634 - console.log('fetched familiar followers', followers); 635 - accountInfoStates.familiarFollowers = 636 - followers[0].accounts.slice(0, FAMILIAR_FOLLOWERS_LIMIT); 637 - 638 - if (!standalone) { 639 - const { value: statuses } = await fetchStatuses; 640 - console.log('fetched statuses', statuses); 641 - const stats = { 642 - total: statuses.length, 643 - originals: 0, 644 - replies: 0, 645 - boosts: 0, 646 - }; 647 - // Categories statuses by type 648 - // - Original posts (not replies to others) 649 - // - Threads (self-replies + 1st original post) 650 - // - Boosts (reblogs) 651 - // - Replies (not-self replies) 652 - statuses.forEach((status) => { 653 - if (status.reblog) { 654 - stats.boosts++; 655 - } else if ( 656 - status.inReplyToAccountId !== currentID && 657 - !!status.inReplyToId 658 - ) { 659 - stats.replies++; 660 - } else { 661 - stats.originals++; 662 - } 663 - }); 664 - 665 - // Count days since last post 666 - stats.daysSinceLastPost = Math.ceil( 667 - (Date.now() - 668 - new Date(statuses[statuses.length - 1].createdAt)) / 669 - 86400000, 670 - ); 671 - 672 - console.log('posting stats', stats); 673 - setPostingStats(stats); 674 - } 675 - } catch (e) { 676 - console.error(e); 677 - } 678 - } 757 + onRelationshipChange({ relationship, currentID }); 679 758 } 680 759 } catch (e) { 681 760 console.error(e); ··· 697 776 const [showTranslatedBio, setShowTranslatedBio] = useState(false); 698 777 const [showAddRemoveLists, setShowAddRemoveLists] = useState(false); 699 778 700 - const hasPostingStats = postingStats?.total >= 3; 701 - const accountLink = instance ? `/${instance}/a/${id}` : `/a/${id}`; 702 - 703 779 return ( 704 780 <> 705 - {hasPostingStats && ( 706 - <Link 707 - to={accountLink} 708 - class="account-metadata-box" 709 - onClick={() => { 710 - states.showAccount = false; 711 - }} 712 - > 713 - <div class="shazam-container"> 714 - <div class="shazam-container-inner"> 715 - <div 716 - class="posting-stats" 717 - title={`${Math.round( 718 - (postingStats.originals / postingStats.total) * 100, 719 - )}% original posts, ${Math.round( 720 - (postingStats.replies / postingStats.total) * 100, 721 - )}% replies, ${Math.round( 722 - (postingStats.boosts / postingStats.total) * 100, 723 - )}% boosts`} 724 - > 725 - <div> 726 - {postingStats.daysSinceLastPost < 365 727 - ? `Last ${postingStats.total} posts in the past 728 - ${postingStats.daysSinceLastPost} day${ 729 - postingStats.daysSinceLastPost > 1 ? 's' : '' 730 - }` 731 - : ` 732 - Last ${postingStats.total} posts in the past year(s) 733 - `} 734 - </div> 735 - <div 736 - class="posting-stats-bar" 737 - style={{ 738 - // [originals | replies | boosts] 739 - '--originals-percentage': `${ 740 - (postingStats.originals / postingStats.total) * 100 741 - }%`, 742 - '--replies-percentage': `${ 743 - ((postingStats.originals + postingStats.replies) / 744 - postingStats.total) * 745 - 100 746 - }%`, 747 - }} 748 - /> 749 - <div class="posting-stats-legends"> 750 - <span class="ib"> 751 - <span class="posting-stats-legend-item posting-stats-legend-item-originals" />{' '} 752 - Original 753 - </span>{' '} 754 - <span class="ib"> 755 - <span class="posting-stats-legend-item posting-stats-legend-item-replies" />{' '} 756 - Replies 757 - </span>{' '} 758 - <span class="ib"> 759 - <span class="posting-stats-legend-item posting-stats-legend-item-boosts" />{' '} 760 - Boosts 761 - </span> 762 - </div> 763 - </div> 764 - </div> 765 - </div> 766 - </Link> 767 - )} 768 781 <p class="actions"> 769 782 <span> 770 783 {followedBy ? (