Add social proof to suggested follows (#4602)
* replace unused `followers` prop with social proof * Introduce 'minimal' version * Gate social proof one explore page, fix space if no desc * Use smaller avis for minimal --------- Co-authored-by: Eric Bailey <git@esb.lol>
This commit is contained in:
		
							parent
							
								
									4360087ced
								
							
						
					
					
						commit
						2d0eefebc3
					
				
					 4 changed files with 64 additions and 75 deletions
				
			
		|  | @ -5,7 +5,6 @@ import { | |||
|   moderateProfile, | ||||
|   ModerationDecision, | ||||
| } from '@atproto/api' | ||||
| import {Trans} from '@lingui/macro' | ||||
| import {useQueryClient} from '@tanstack/react-query' | ||||
| 
 | ||||
| import {useProfileShadow} from '#/state/cache/profile-shadow' | ||||
|  | @ -19,12 +18,16 @@ import {sanitizeDisplayName} from 'lib/strings/display-names' | |||
| import {sanitizeHandle} from 'lib/strings/handles' | ||||
| import {s} from 'lib/styles' | ||||
| import {precacheProfile} from 'state/queries/profile' | ||||
| import {atoms as a} from '#/alf' | ||||
| import { | ||||
|   KnownFollowers, | ||||
|   shouldShowKnownFollowers, | ||||
| } from '#/components/KnownFollowers' | ||||
| import {Link} from '../util/Link' | ||||
| import {Text} from '../util/text/Text' | ||||
| import {PreviewableUserAvatar} from '../util/UserAvatar' | ||||
| import {FollowButton} from './FollowButton' | ||||
| import hairlineWidth = StyleSheet.hairlineWidth | ||||
| import {atoms as a} from '#/alf' | ||||
| import * as Pills from '#/components/Pills' | ||||
| 
 | ||||
| export function ProfileCard({ | ||||
|  | @ -33,22 +36,22 @@ export function ProfileCard({ | |||
|   noModFilter, | ||||
|   noBg, | ||||
|   noBorder, | ||||
|   followers, | ||||
|   renderButton, | ||||
|   onPress, | ||||
|   style, | ||||
|   showKnownFollowers, | ||||
| }: { | ||||
|   testID?: string | ||||
|   profile: AppBskyActorDefs.ProfileViewBasic | ||||
|   noModFilter?: boolean | ||||
|   noBg?: boolean | ||||
|   noBorder?: boolean | ||||
|   followers?: AppBskyActorDefs.ProfileView[] | undefined | ||||
|   renderButton?: ( | ||||
|     profile: Shadow<AppBskyActorDefs.ProfileViewBasic>, | ||||
|   ) => React.ReactNode | ||||
|   onPress?: () => void | ||||
|   style?: StyleProp<ViewStyle> | ||||
|   showKnownFollowers?: boolean | ||||
| }) { | ||||
|   const queryClient = useQueryClient() | ||||
|   const pal = usePalette('default') | ||||
|  | @ -70,6 +73,11 @@ export function ProfileCard({ | |||
|     return null | ||||
|   } | ||||
| 
 | ||||
|   const knownFollowersVisible = | ||||
|     showKnownFollowers && | ||||
|     shouldShowKnownFollowers(profile.viewer?.knownFollowers) && | ||||
|     moderationOpts | ||||
| 
 | ||||
|   return ( | ||||
|     <Link | ||||
|       testID={testID} | ||||
|  | @ -118,14 +126,30 @@ export function ProfileCard({ | |||
|           <View style={styles.layoutButton}>{renderButton(profile)}</View> | ||||
|         ) : undefined} | ||||
|       </View> | ||||
|       {profile.description ? ( | ||||
|       {profile.description || knownFollowersVisible ? ( | ||||
|         <View style={styles.details}> | ||||
|           <Text style={pal.text} numberOfLines={4}> | ||||
|             {profile.description as string} | ||||
|           </Text> | ||||
|           {profile.description ? ( | ||||
|             <Text style={pal.text} numberOfLines={4}> | ||||
|               {profile.description as string} | ||||
|             </Text> | ||||
|           ) : null} | ||||
|           {knownFollowersVisible ? ( | ||||
|             <View | ||||
|               style={[ | ||||
|                 a.flex_row, | ||||
|                 a.align_center, | ||||
|                 a.gap_sm, | ||||
|                 !!profile.description && a.mt_md, | ||||
|               ]}> | ||||
|               <KnownFollowers | ||||
|                 minimal | ||||
|                 profile={profile} | ||||
|                 moderationOpts={moderationOpts} | ||||
|               /> | ||||
|             </View> | ||||
|           ) : null} | ||||
|         </View> | ||||
|       ) : null} | ||||
|       <FollowersList followers={followers} /> | ||||
|     </Link> | ||||
|   ) | ||||
| } | ||||
|  | @ -155,73 +179,20 @@ export function ProfileCardPills({ | |||
|   ) | ||||
| } | ||||
| 
 | ||||
| function FollowersList({ | ||||
|   followers, | ||||
| }: { | ||||
|   followers?: AppBskyActorDefs.ProfileView[] | undefined | ||||
| }) { | ||||
|   const pal = usePalette('default') | ||||
|   const moderationOpts = useModerationOpts() | ||||
| 
 | ||||
|   const followersWithMods = React.useMemo(() => { | ||||
|     if (!followers || !moderationOpts) { | ||||
|       return [] | ||||
|     } | ||||
| 
 | ||||
|     return followers | ||||
|       .map(f => ({ | ||||
|         f, | ||||
|         mod: moderateProfile(f, moderationOpts), | ||||
|       })) | ||||
|       .filter(({mod}) => !mod.ui('profileList').filter) | ||||
|   }, [followers, moderationOpts]) | ||||
| 
 | ||||
|   if (!followersWithMods?.length) { | ||||
|     return null | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|     <View style={styles.followedBy}> | ||||
|       <Text | ||||
|         type="sm" | ||||
|         style={[styles.followsByDesc, pal.textLight]} | ||||
|         numberOfLines={2} | ||||
|         lineHeight={1.2}> | ||||
|         <Trans> | ||||
|           Followed by{' '} | ||||
|           {followersWithMods.map(({f}) => f.displayName || f.handle).join(', ')} | ||||
|         </Trans> | ||||
|       </Text> | ||||
|       {followersWithMods.slice(0, 3).map(({f, mod}) => ( | ||||
|         <View key={f.did} style={styles.followedByAviContainer}> | ||||
|           <View style={[styles.followedByAvi, pal.view]}> | ||||
|             <PreviewableUserAvatar | ||||
|               size={32} | ||||
|               profile={f} | ||||
|               moderation={mod.ui('avatar')} | ||||
|               type={f.associated?.labeler ? 'labeler' : 'user'} | ||||
|             /> | ||||
|           </View> | ||||
|         </View> | ||||
|       ))} | ||||
|     </View> | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| export function ProfileCardWithFollowBtn({ | ||||
|   profile, | ||||
|   noBg, | ||||
|   noBorder, | ||||
|   followers, | ||||
|   onPress, | ||||
|   logContext = 'ProfileCard', | ||||
|   showKnownFollowers, | ||||
| }: { | ||||
|   profile: AppBskyActorDefs.ProfileViewBasic | ||||
|   profile: AppBskyActorDefs.ProfileView | ||||
|   noBg?: boolean | ||||
|   noBorder?: boolean | ||||
|   followers?: AppBskyActorDefs.ProfileView[] | undefined | ||||
|   onPress?: () => void | ||||
|   logContext?: 'ProfileCard' | 'StarterPackProfilesList' | ||||
|   showKnownFollowers?: boolean | ||||
| }) { | ||||
|   const {currentAccount} = useSession() | ||||
|   const isMe = profile.did === currentAccount?.did | ||||
|  | @ -231,7 +202,6 @@ export function ProfileCardWithFollowBtn({ | |||
|       profile={profile} | ||||
|       noBg={noBg} | ||||
|       noBorder={noBorder} | ||||
|       followers={followers} | ||||
|       renderButton={ | ||||
|         isMe | ||||
|           ? undefined | ||||
|  | @ -240,6 +210,7 @@ export function ProfileCardWithFollowBtn({ | |||
|             ) | ||||
|       } | ||||
|       onPress={onPress} | ||||
|       showKnownFollowers={!isMe && showKnownFollowers} | ||||
|     /> | ||||
|   ) | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue