Merge the suggested actors model with the general suggestion system (#343)
parent
f20fb92dc3
commit
4f814207bc
|
@ -1,7 +1,7 @@
|
|||
import {makeAutoObservable, runInAction} from 'mobx'
|
||||
import {AppBskyActorProfile as Profile} from '@atproto/api'
|
||||
import shuffle from 'lodash.shuffle'
|
||||
import {RootStoreModel} from './root-store'
|
||||
import {RootStoreModel} from '../root-store'
|
||||
import {cleanError} from 'lib/strings/errors'
|
||||
import {bundleAsync} from 'lib/async/bundle'
|
||||
import {SUGGESTED_FOLLOWS} from 'lib/constants'
|
||||
|
@ -10,7 +10,7 @@ const PAGE_SIZE = 30
|
|||
|
||||
export type SuggestedActor = Profile.ViewBasic | Profile.View
|
||||
|
||||
export class SuggestedActorsViewModel {
|
||||
export class SuggestedActorsModel {
|
||||
// state
|
||||
pageSize = PAGE_SIZE
|
||||
isLoading = false
|
|
@ -11,7 +11,11 @@ export const SuggestedFollows = ({
|
|||
suggestions,
|
||||
}: {
|
||||
title: string
|
||||
suggestions: (AppBskyActorRef.WithInfo | RefWithInfoAndFollowers)[]
|
||||
suggestions: (
|
||||
| AppBskyActorRef.WithInfo
|
||||
| RefWithInfoAndFollowers
|
||||
| AppBskyActorProfile.View
|
||||
)[]
|
||||
}) => {
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
|
@ -30,7 +34,11 @@ export const SuggestedFollows = ({
|
|||
avatar={item.avatar}
|
||||
noBg
|
||||
noBorder
|
||||
description=""
|
||||
description={
|
||||
item.description
|
||||
? (item as AppBskyActorProfile.View).description
|
||||
: ''
|
||||
}
|
||||
followers={
|
||||
item.followers
|
||||
? (item.followers as AppBskyActorProfile.View[])
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
import React from 'react'
|
||||
import {ActivityIndicator, StyleSheet, View} from 'react-native'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {useStores} from 'state/index'
|
||||
import {SuggestedActorsViewModel} from 'state/models/suggested-actors-view'
|
||||
import {ProfileCardWithFollowBtn} from '../profile/ProfileCard'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {s} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
|
||||
export const WhoToFollow = observer(() => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const suggestedActorsView = React.useMemo<SuggestedActorsViewModel>(
|
||||
() => new SuggestedActorsViewModel(store, {pageSize: 15}),
|
||||
[store],
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
suggestedActorsView.loadMore(true)
|
||||
}, [store, suggestedActorsView])
|
||||
|
||||
return (
|
||||
<>
|
||||
{(suggestedActorsView.hasContent || suggestedActorsView.isLoading) && (
|
||||
<Text type="title" style={[styles.heading, pal.text]}>
|
||||
Who to follow
|
||||
</Text>
|
||||
)}
|
||||
{suggestedActorsView.hasContent && (
|
||||
<>
|
||||
<View style={[pal.border, styles.bottomBorder]}>
|
||||
{suggestedActorsView.suggestions.map(item => (
|
||||
<ProfileCardWithFollowBtn
|
||||
key={item.did}
|
||||
did={item.did}
|
||||
declarationCid={item.declaration.cid}
|
||||
handle={item.handle}
|
||||
displayName={item.displayName}
|
||||
avatar={item.avatar}
|
||||
description={item.description}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
{suggestedActorsView.isLoading && (
|
||||
<View style={s.mt10}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
heading: {
|
||||
fontWeight: 'bold',
|
||||
paddingHorizontal: 12,
|
||||
paddingBottom: 8,
|
||||
},
|
||||
|
||||
bottomBorder: {
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
})
|
|
@ -2,15 +2,21 @@ import React from 'react'
|
|||
import {StyleSheet, View} from 'react-native'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {FoafsModel} from 'state/models/discovery/foafs'
|
||||
import {WhoToFollow} from 'view/com/discover/WhoToFollow'
|
||||
import {SuggestedActorsModel} from 'state/models/discovery/suggested-actors'
|
||||
import {SuggestedFollows} from 'view/com/discover/SuggestedFollows'
|
||||
import {ProfileCardFeedLoadingPlaceholder} from 'view/com/util/LoadingPlaceholder'
|
||||
|
||||
export const Suggestions = observer(({foafs}: {foafs: FoafsModel}) => {
|
||||
if (foafs.isLoading) {
|
||||
export const Suggestions = observer(
|
||||
({
|
||||
foafs,
|
||||
suggestedActors,
|
||||
}: {
|
||||
foafs: FoafsModel
|
||||
suggestedActors: SuggestedActorsModel
|
||||
}) => {
|
||||
if (foafs.isLoading || suggestedActors.isLoading) {
|
||||
return <ProfileCardFeedLoadingPlaceholder />
|
||||
}
|
||||
if (foafs.hasContent) {
|
||||
return (
|
||||
<>
|
||||
{foafs.popular.length > 0 && (
|
||||
|
@ -21,7 +27,14 @@ export const Suggestions = observer(({foafs}: {foafs: FoafsModel}) => {
|
|||
/>
|
||||
</View>
|
||||
)}
|
||||
<WhoToFollow />
|
||||
{suggestedActors.hasContent && (
|
||||
<View style={styles.suggestions}>
|
||||
<SuggestedFollows
|
||||
title="Suggested follows"
|
||||
suggestions={suggestedActors.suggestions}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
{foafs.sources.map((source, i) => {
|
||||
const item = foafs.foafs.get(source)
|
||||
if (!item || item.follows.length === 0) {
|
||||
|
@ -38,9 +51,8 @@ export const Suggestions = observer(({foafs}: {foafs: FoafsModel}) => {
|
|||
})}
|
||||
</>
|
||||
)
|
||||
}
|
||||
return <WhoToFollow />
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
suggestions: {
|
||||
|
|
|
@ -19,6 +19,7 @@ import {useStores} from 'state/index'
|
|||
import {UserAutocompleteViewModel} from 'state/models/user-autocomplete-view'
|
||||
import {SearchUIModel} from 'state/models/ui/search'
|
||||
import {FoafsModel} from 'state/models/discovery/foafs'
|
||||
import {SuggestedActorsModel} from 'state/models/discovery/suggested-actors'
|
||||
import {HeaderWithInput} from 'view/com/search/HeaderWithInput'
|
||||
import {Suggestions} from 'view/com/search/Suggestions'
|
||||
import {SearchResults} from 'view/com/search/SearchResults'
|
||||
|
@ -44,6 +45,10 @@ export const SearchScreen = withAuthRequired(
|
|||
() => new FoafsModel(store),
|
||||
[store],
|
||||
)
|
||||
const suggestedActors = React.useMemo<SuggestedActorsModel>(
|
||||
() => new SuggestedActorsModel(store),
|
||||
[store],
|
||||
)
|
||||
const [searchUIModel, setSearchUIModel] = React.useState<
|
||||
SearchUIModel | undefined
|
||||
>()
|
||||
|
@ -65,9 +70,12 @@ export const SearchScreen = withAuthRequired(
|
|||
if (!foafs.hasData) {
|
||||
foafs.fetch()
|
||||
}
|
||||
if (!suggestedActors.hasLoaded) {
|
||||
suggestedActors.loadMore(true)
|
||||
}
|
||||
|
||||
return cleanup
|
||||
}, [store, autocompleteView, foafs]),
|
||||
}, [store, autocompleteView, foafs, suggestedActors]),
|
||||
)
|
||||
|
||||
const onChangeQuery = React.useCallback(
|
||||
|
@ -163,7 +171,7 @@ export const SearchScreen = withAuthRequired(
|
|||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
<Suggestions foafs={foafs} />
|
||||
<Suggestions foafs={foafs} suggestedActors={suggestedActors} />
|
||||
)}
|
||||
<View style={s.footerSpacer} />
|
||||
</ScrollView>
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react'
|
|||
import {StyleSheet, View} from 'react-native'
|
||||
import {SearchUIModel} from 'state/models/ui/search'
|
||||
import {FoafsModel} from 'state/models/discovery/foafs'
|
||||
import {SuggestedActorsModel} from 'state/models/discovery/suggested-actors'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {ScrollView} from 'view/com/util/Views'
|
||||
import {Suggestions} from 'view/com/search/Suggestions'
|
||||
|
@ -24,6 +25,10 @@ export const SearchScreen = withAuthRequired(
|
|||
() => new FoafsModel(store),
|
||||
[store],
|
||||
)
|
||||
const suggestedActors = React.useMemo<SuggestedActorsModel>(
|
||||
() => new SuggestedActorsModel(store),
|
||||
[store],
|
||||
)
|
||||
const searchUIModel = React.useMemo<SearchUIModel | undefined>(
|
||||
() => (route.params.q ? new SearchUIModel(store) : undefined),
|
||||
[route.params.q, store],
|
||||
|
@ -36,7 +41,10 @@ export const SearchScreen = withAuthRequired(
|
|||
if (!foafs.hasData) {
|
||||
foafs.fetch()
|
||||
}
|
||||
}, [foafs, searchUIModel, route.params.q])
|
||||
if (!suggestedActors.hasLoaded) {
|
||||
suggestedActors.loadMore(true)
|
||||
}
|
||||
}, [foafs, suggestedActors, searchUIModel, route.params.q])
|
||||
|
||||
if (searchUIModel) {
|
||||
return <SearchResults model={searchUIModel} />
|
||||
|
@ -47,7 +55,7 @@ export const SearchScreen = withAuthRequired(
|
|||
testID="searchScrollView"
|
||||
style={[pal.view, styles.container]}
|
||||
scrollEventThrottle={100}>
|
||||
<Suggestions foafs={foafs} />
|
||||
<Suggestions foafs={foafs} suggestedActors={suggestedActors} />
|
||||
<View style={s.footerSpacer} />
|
||||
</ScrollView>
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue