add for feeds
This commit is contained in:
@@ -1,40 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import {View} from 'react-native'
|
|
||||||
import {Trans} from '@lingui/macro'
|
|
||||||
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
|
||||||
import {Hashtag_Stroke2_Corner0_Rounded as Hashtag} from '#/components/icons/Hashtag'
|
|
||||||
import {UserCircle_Stroke2_Corner0_Rounded as UserCircle} from '#/components/icons/UserCircle'
|
|
||||||
import {Text} from '#/components/Typography'
|
|
||||||
|
|
||||||
export function WizardListEmpty({type}: {type: 'profiles' | 'feeds'}) {
|
|
||||||
const t = useTheme()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View
|
|
||||||
style={[a.flex_1, a.px_md, a.align_center, a.gap_md, {marginTop: 100}]}>
|
|
||||||
{type === 'profiles' ? (
|
|
||||||
<UserCircle
|
|
||||||
width={100}
|
|
||||||
height={100}
|
|
||||||
style={t.atoms.text_contrast_medium}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Hashtag
|
|
||||||
width={100}
|
|
||||||
height={100}
|
|
||||||
style={t.atoms.text_contrast_medium}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Text style={[a.text_md, a.text_center, t.atoms.text_contrast_medium]}>
|
|
||||||
{type === 'profiles' ? (
|
|
||||||
<Trans>
|
|
||||||
Search for people that you want to suggest others to follow
|
|
||||||
</Trans>
|
|
||||||
) : (
|
|
||||||
<Trans>Add some cool feeds!</Trans>
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,17 @@
|
|||||||
import React from 'react'
|
import React, {useState} from 'react'
|
||||||
import {ListRenderItemInfo} from 'react-native'
|
import {ListRenderItemInfo, View} from 'react-native'
|
||||||
import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
|
import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
|
||||||
|
import debounce from 'lodash.debounce'
|
||||||
|
|
||||||
|
import {
|
||||||
|
useGetPopularFeedsQuery,
|
||||||
|
useSearchPopularFeedsMutation,
|
||||||
|
} from 'state/queries/feed'
|
||||||
|
import {SearchInput} from 'view/com/util/forms/SearchInput'
|
||||||
import {List} from 'view/com/util/List'
|
import {List} from 'view/com/util/List'
|
||||||
import {useWizardState} from '#/screens/StarterPack/Wizard/State'
|
import {useWizardState} from '#/screens/StarterPack/Wizard/State'
|
||||||
import {atoms as a} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
import {WizardFeedCard} from '#/components/StarterPack/Wizard/WizardFeedCard'
|
import {WizardFeedCard} from '#/components/StarterPack/Wizard/WizardFeedCard'
|
||||||
import {WizardListEmpty} from '#/components/StarterPack/Wizard/WizardListEmpty'
|
|
||||||
|
|
||||||
function keyExtractor(item: GeneratorView) {
|
function keyExtractor(item: GeneratorView) {
|
||||||
return item.uri
|
return item.uri
|
||||||
@@ -14,18 +19,54 @@ function keyExtractor(item: GeneratorView) {
|
|||||||
|
|
||||||
export function StepFeeds() {
|
export function StepFeeds() {
|
||||||
const [state, dispatch] = useWizardState()
|
const [state, dispatch] = useWizardState()
|
||||||
|
const [query, setQuery] = useState('')
|
||||||
|
|
||||||
|
const {data: popularFeedsPages, fetchNextPage} = useGetPopularFeedsQuery()
|
||||||
|
|
||||||
|
const popularFeeds =
|
||||||
|
popularFeedsPages?.pages.flatMap(page => page.feeds) || []
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: searchedFeeds,
|
||||||
|
mutate: search,
|
||||||
|
reset: resetSearch,
|
||||||
|
} = useSearchPopularFeedsMutation()
|
||||||
|
|
||||||
|
const debouncedSearch = React.useMemo(
|
||||||
|
() => debounce(q => search(q), 500), // debounce for 500ms
|
||||||
|
[search],
|
||||||
|
)
|
||||||
|
|
||||||
|
const onChangeQuery = (text: string) => {
|
||||||
|
setQuery(text)
|
||||||
|
if (text.length > 1) {
|
||||||
|
debouncedSearch(text)
|
||||||
|
} else {
|
||||||
|
resetSearch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const renderItem = ({item}: ListRenderItemInfo<GeneratorView>) => {
|
const renderItem = ({item}: ListRenderItemInfo<GeneratorView>) => {
|
||||||
return <WizardFeedCard generator={item} state={state} dispatch={dispatch} />
|
return <WizardFeedCard generator={item} state={state} dispatch={dispatch} />
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List
|
<>
|
||||||
data={state.feeds}
|
<View style={[a.my_sm, a.px_md, {height: 40}]}>
|
||||||
renderItem={renderItem}
|
<SearchInput
|
||||||
keyExtractor={keyExtractor}
|
query={query}
|
||||||
style={[a.flex_1]}
|
onChangeQuery={onChangeQuery}
|
||||||
ListEmptyComponent={<WizardListEmpty type="feeds" />}
|
onPressCancelSearch={() => setQuery('')}
|
||||||
/>
|
onSubmitQuery={() => {}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<List
|
||||||
|
data={query ? searchedFeeds : popularFeeds}
|
||||||
|
renderItem={renderItem}
|
||||||
|
keyExtractor={keyExtractor}
|
||||||
|
style={[a.flex_1]}
|
||||||
|
onEndReached={!query ? () => fetchNextPage() : undefined}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, {useState} from 'react'
|
import React, {useState} from 'react'
|
||||||
import {ListRenderItemInfo, View} from 'react-native'
|
import {ListRenderItemInfo, View} from 'react-native'
|
||||||
|
import {KeyboardAwareScrollView} from 'react-native-keyboard-controller'
|
||||||
import {AppBskyActorDefs} from '@atproto/api'
|
import {AppBskyActorDefs} from '@atproto/api'
|
||||||
|
|
||||||
import {useActorAutocompleteQuery} from 'state/queries/actor-autocomplete'
|
import {useActorAutocompleteQuery} from 'state/queries/actor-autocomplete'
|
||||||
@@ -54,6 +55,7 @@ export function StepProfiles() {
|
|||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
keyExtractor={keyExtractor}
|
keyExtractor={keyExtractor}
|
||||||
onEndReached={!query ? () => fetchNextPage() : undefined}
|
onEndReached={!query ? () => fetchNextPage() : undefined}
|
||||||
|
renderScrollComponent={props => <KeyboardAwareScrollView {...props} />}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {Keyboard, View} from 'react-native'
|
import {Keyboard, View} from 'react-native'
|
||||||
import {KeyboardAwareScrollView} from 'react-native-keyboard-controller'
|
import {KeyboardAwareScrollView} from 'react-native-keyboard-controller'
|
||||||
import {AppBskyActorDefs, AppBskyFeedDefs} from '@atproto/api'
|
import {AppBskyActorDefs} from '@atproto/api'
|
||||||
import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
|
import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
|
||||||
import {msg, Plural, Trans} from '@lingui/macro'
|
import {msg, Plural, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
@@ -186,20 +186,21 @@ function WizardInner() {
|
|||||||
<StepView />
|
<StepView />
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
{state.currentStep === 'Details' && (
|
{state.currentStep === 'Details' ? (
|
||||||
<Button
|
<Button
|
||||||
label={uiStrings.nextBtn}
|
label={uiStrings.nextBtn}
|
||||||
variant="solid"
|
variant="solid"
|
||||||
color="primary"
|
color="primary"
|
||||||
size="medium"
|
size="medium"
|
||||||
style={[a.mx_xl, a.my_5xl]}
|
style={[a.mx_xl, a.my_5xl]}
|
||||||
onPress={onNext}>
|
onPress={onNext}
|
||||||
|
disabled={!state.canNext}>
|
||||||
<ButtonText>{uiStrings.nextBtn}</ButtonText>
|
<ButtonText>{uiStrings.nextBtn}</ButtonText>
|
||||||
</Button>
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Footer onNext={onNext} nextBtnText={uiStrings.nextBtn} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Footer onNext={onNext} nextBtnText={uiStrings.nextBtn} />
|
|
||||||
|
|
||||||
{(state.currentStep === 'Profiles' || state.currentStep === 'Feeds') && (
|
{(state.currentStep === 'Profiles' || state.currentStep === 'Feeds') && (
|
||||||
<WizardAddDialog
|
<WizardAddDialog
|
||||||
control={addDialogControl}
|
control={addDialogControl}
|
||||||
@@ -274,9 +275,9 @@ function Footer({
|
|||||||
},
|
},
|
||||||
]}>
|
]}>
|
||||||
<View style={[a.flex_row, a.gap_xs]}>
|
<View style={[a.flex_row, a.gap_xs]}>
|
||||||
{items.slice(0, 5).map(p => (
|
{items.slice(0, 5).map((p, index) => (
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
key={p.did}
|
key={index}
|
||||||
avatar={p.avatar}
|
avatar={p.avatar}
|
||||||
size={28}
|
size={28}
|
||||||
type={state.currentStep === 'Profiles' ? 'user' : 'algo'}
|
type={state.currentStep === 'Profiles' ? 'user' : 'algo'}
|
||||||
@@ -363,11 +364,11 @@ function Footer({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getName(item: AppBskyActorDefs.ProfileViewBasic | GeneratorView) {
|
function getName(item: AppBskyActorDefs.ProfileViewBasic | GeneratorView) {
|
||||||
if (AppBskyActorDefs.isProfileView(item)) {
|
// TODO hack for now since these are not full profiles and wont validate
|
||||||
return enforceLen(item.displayName || item.handle, 16)
|
if (typeof item.displayName === 'string') {
|
||||||
}
|
return enforceLen(item.displayName, 16, true)
|
||||||
if (AppBskyFeedDefs.isGeneratorView(item)) {
|
} else if (typeof item.handle === 'string') {
|
||||||
return enforceLen(item.displayName, 16)
|
return enforceLen(item.handle, 16, true)
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user