refactor list card items, apply moderation
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import React, {useRef} from 'react'
|
import React, {useRef} from 'react'
|
||||||
import type {ListRenderItemInfo} from 'react-native'
|
import type {ListRenderItemInfo} from 'react-native'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {AppBskyActorDefs} from '@atproto/api'
|
import {AppBskyActorDefs, ModerationOpts} 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 {BottomSheetFlatListMethods} from '@discord/bottom-sheet'
|
import {BottomSheetFlatListMethods} from '@discord/bottom-sheet'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
@@ -13,8 +13,10 @@ import {WizardAction, WizardState} from '#/screens/StarterPack/Wizard/State'
|
|||||||
import {atoms as a, native, useTheme, web} from '#/alf'
|
import {atoms as a, native, useTheme, web} from '#/alf'
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
import * as Dialog from '#/components/Dialog'
|
import * as Dialog from '#/components/Dialog'
|
||||||
import {WizardFeedCard} from '#/components/StarterPack/Wizard/WizardFeedCard'
|
import {
|
||||||
import {WizardProfileCard} from '#/components/StarterPack/Wizard/WizardProfileCard'
|
WizardFeedCard,
|
||||||
|
WizardProfileCard,
|
||||||
|
} from '#/components/StarterPack/Wizard/WizardListCard'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
function keyExtractor(
|
function keyExtractor(
|
||||||
@@ -28,10 +30,12 @@ export function WizardEditListDialog({
|
|||||||
control,
|
control,
|
||||||
state,
|
state,
|
||||||
dispatch,
|
dispatch,
|
||||||
|
moderationOpts,
|
||||||
}: {
|
}: {
|
||||||
control: Dialog.DialogControlProps
|
control: Dialog.DialogControlProps
|
||||||
state: WizardState
|
state: WizardState
|
||||||
dispatch: (action: WizardAction) => void
|
dispatch: (action: WizardAction) => void
|
||||||
|
moderationOpts: ModerationOpts
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
@@ -53,9 +57,19 @@ export function WizardEditListDialog({
|
|||||||
|
|
||||||
const renderItem = ({item}: ListRenderItemInfo<any>) =>
|
const renderItem = ({item}: ListRenderItemInfo<any>) =>
|
||||||
state.currentStep === 'Profiles' ? (
|
state.currentStep === 'Profiles' ? (
|
||||||
<WizardProfileCard profile={item} state={state} dispatch={dispatch} />
|
<WizardProfileCard
|
||||||
|
profile={item}
|
||||||
|
state={state}
|
||||||
|
dispatch={dispatch}
|
||||||
|
moderationOpts={moderationOpts}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<WizardFeedCard generator={item} state={state} dispatch={dispatch} />
|
<WizardFeedCard
|
||||||
|
generator={item}
|
||||||
|
state={state}
|
||||||
|
dispatch={dispatch}
|
||||||
|
moderationOpts={moderationOpts}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import {Keyboard, Pressable, View} from 'react-native'
|
|
||||||
import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
|
|
||||||
import {msg} from '@lingui/macro'
|
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
|
|
||||||
import {DISCOVER_FEED_URI} from 'lib/constants'
|
|
||||||
import {isWeb} from 'platform/detection'
|
|
||||||
import {UserAvatar} from 'view/com/util/UserAvatar'
|
|
||||||
import {WizardAction, WizardState} from '#/screens/StarterPack/Wizard/State'
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
|
||||||
import * as Toggle from '#/components/forms/Toggle'
|
|
||||||
import {Checkbox} from '#/components/forms/Toggle'
|
|
||||||
import {Text} from '#/components/Typography'
|
|
||||||
|
|
||||||
export function WizardFeedCard({
|
|
||||||
generator,
|
|
||||||
state,
|
|
||||||
dispatch,
|
|
||||||
}: {
|
|
||||||
generator: GeneratorView
|
|
||||||
state: WizardState
|
|
||||||
dispatch: (action: WizardAction) => void
|
|
||||||
}) {
|
|
||||||
const {_} = useLingui()
|
|
||||||
const t = useTheme()
|
|
||||||
|
|
||||||
const isDiscover = generator.uri === DISCOVER_FEED_URI
|
|
||||||
const includesFeed =
|
|
||||||
isDiscover || state.feeds.some(f => f.uri === generator.uri)
|
|
||||||
const isDisabled = isDiscover || (!includesFeed && state.feeds.length >= 3)
|
|
||||||
|
|
||||||
const onPressAddRemove = () => {
|
|
||||||
if (isDisabled) return
|
|
||||||
|
|
||||||
Keyboard.dismiss()
|
|
||||||
if (includesFeed) {
|
|
||||||
dispatch({type: 'RemoveFeed', feedUri: generator.uri})
|
|
||||||
} else {
|
|
||||||
dispatch({type: 'AddFeed', feed: generator})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Pressable
|
|
||||||
accessibilityRole="button"
|
|
||||||
style={[
|
|
||||||
a.flex_row,
|
|
||||||
a.align_center,
|
|
||||||
a.px_lg,
|
|
||||||
a.py_sm,
|
|
||||||
a.gap_md,
|
|
||||||
a.border_b,
|
|
||||||
t.atoms.border_contrast_low,
|
|
||||||
// @ts-expect-error web only
|
|
||||||
isWeb && {
|
|
||||||
cursor: 'default',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
onPress={onPressAddRemove}>
|
|
||||||
<UserAvatar type="algo" size={45} avatar={generator.avatar} />
|
|
||||||
<View style={[a.flex_1]}>
|
|
||||||
<Text style={[a.flex_1, a.font_bold, a.text_md]} numberOfLines={1}>
|
|
||||||
{generator.displayName}
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
style={[a.flex_1, t.atoms.text_contrast_medium]}
|
|
||||||
numberOfLines={1}>
|
|
||||||
{_(msg`Feed by @${generator.creator.handle}`)}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<Toggle.Item
|
|
||||||
name={_(msg`Person toggle`)}
|
|
||||||
label={
|
|
||||||
includesFeed
|
|
||||||
? _(msg`Remove ${generator.displayName} from starter pack`)
|
|
||||||
: _(msg`Add ${generator.displayName} to starter pack`)
|
|
||||||
}
|
|
||||||
value={includesFeed}
|
|
||||||
disabled={isDisabled}
|
|
||||||
onChange={onPressAddRemove}>
|
|
||||||
<Checkbox />
|
|
||||||
</Toggle.Item>
|
|
||||||
</Pressable>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {Keyboard, Pressable, View} from 'react-native'
|
||||||
|
import {
|
||||||
|
AppBskyActorDefs,
|
||||||
|
AppBskyFeedDefs,
|
||||||
|
moderateFeedGenerator,
|
||||||
|
moderateProfile,
|
||||||
|
ModerationOpts,
|
||||||
|
ModerationUI,
|
||||||
|
} from '@atproto/api'
|
||||||
|
import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
|
||||||
|
import {msg} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {DISCOVER_FEED_URI} from 'lib/constants'
|
||||||
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
|
import {sanitizeHandle} from 'lib/strings/handles'
|
||||||
|
import {isWeb} from 'platform/detection'
|
||||||
|
import {useSession} from 'state/session'
|
||||||
|
import {UserAvatar} from 'view/com/util/UserAvatar'
|
||||||
|
import {WizardAction, WizardState} from '#/screens/StarterPack/Wizard/State'
|
||||||
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
import * as Toggle from '#/components/forms/Toggle'
|
||||||
|
import {Checkbox} from '#/components/forms/Toggle'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
|
function WizardListCard({
|
||||||
|
type,
|
||||||
|
displayName,
|
||||||
|
subtitle,
|
||||||
|
onPress,
|
||||||
|
avatar,
|
||||||
|
included,
|
||||||
|
disabled,
|
||||||
|
moderationUi,
|
||||||
|
}: {
|
||||||
|
type: 'user' | 'algo'
|
||||||
|
profile?: AppBskyActorDefs.ProfileViewBasic
|
||||||
|
feed?: AppBskyFeedDefs.GeneratorView
|
||||||
|
displayName: string
|
||||||
|
subtitle: string
|
||||||
|
onPress: () => void
|
||||||
|
avatar?: string
|
||||||
|
included?: boolean
|
||||||
|
disabled?: boolean
|
||||||
|
moderationUi: ModerationUI
|
||||||
|
}) {
|
||||||
|
const t = useTheme()
|
||||||
|
const {_} = useLingui()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Pressable
|
||||||
|
accessibilityRole="button"
|
||||||
|
style={[
|
||||||
|
a.flex_row,
|
||||||
|
a.align_center,
|
||||||
|
a.px_lg,
|
||||||
|
a.py_sm,
|
||||||
|
a.gap_md,
|
||||||
|
a.border_b,
|
||||||
|
t.atoms.border_contrast_low,
|
||||||
|
// @ts-expect-error web only
|
||||||
|
isWeb && {
|
||||||
|
cursor: 'default',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
onPress={onPress}>
|
||||||
|
<UserAvatar
|
||||||
|
size={45}
|
||||||
|
avatar={avatar}
|
||||||
|
moderation={moderationUi}
|
||||||
|
type={type}
|
||||||
|
/>
|
||||||
|
<View style={[a.flex_1]}>
|
||||||
|
<Text style={[a.flex_1, a.font_bold, a.text_md]} numberOfLines={1}>
|
||||||
|
{displayName}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={[a.flex_1, t.atoms.text_contrast_medium]}
|
||||||
|
numberOfLines={1}>
|
||||||
|
{subtitle}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Toggle.Item
|
||||||
|
name={type === 'user' ? _(msg`Person toggle`) : _(msg`Feed toggle`)}
|
||||||
|
label={
|
||||||
|
included
|
||||||
|
? _(msg`Remove ${displayName} from starter pack`)
|
||||||
|
: _(msg`Add ${displayName} to starter pack`)
|
||||||
|
}
|
||||||
|
value={included}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={onPress}>
|
||||||
|
<Checkbox />
|
||||||
|
</Toggle.Item>
|
||||||
|
</Pressable>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WizardProfileCard({
|
||||||
|
state,
|
||||||
|
dispatch,
|
||||||
|
profile,
|
||||||
|
moderationOpts,
|
||||||
|
}: {
|
||||||
|
state: WizardState
|
||||||
|
dispatch: (action: WizardAction) => void
|
||||||
|
profile: AppBskyActorDefs.ProfileViewBasic
|
||||||
|
moderationOpts: ModerationOpts
|
||||||
|
}) {
|
||||||
|
const {currentAccount} = useSession()
|
||||||
|
|
||||||
|
const included = state.profiles.some(p => p.did === profile.did)
|
||||||
|
const isMe = profile.did === currentAccount?.did
|
||||||
|
const disabled = isMe || state.profiles.length >= 50
|
||||||
|
const moderationUi = moderateProfile(profile, moderationOpts).ui('avatar')
|
||||||
|
const displayName = profile.displayName
|
||||||
|
? sanitizeDisplayName(profile.displayName)
|
||||||
|
: `@${sanitizeHandle(profile.handle)}`
|
||||||
|
|
||||||
|
const onPress = () => {
|
||||||
|
if (disabled) return
|
||||||
|
|
||||||
|
Keyboard.dismiss()
|
||||||
|
if (profile.did === currentAccount?.did) return
|
||||||
|
|
||||||
|
if (!included) {
|
||||||
|
dispatch({type: 'AddProfile', profile})
|
||||||
|
} else {
|
||||||
|
dispatch({type: 'RemoveProfile', profileDid: profile.did})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WizardListCard
|
||||||
|
type="user"
|
||||||
|
displayName={displayName}
|
||||||
|
subtitle={`@${sanitizeHandle(profile.handle)}`}
|
||||||
|
onPress={onPress}
|
||||||
|
avatar={profile.avatar}
|
||||||
|
included={included}
|
||||||
|
disabled={disabled}
|
||||||
|
moderationUi={moderationUi}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WizardFeedCard({
|
||||||
|
generator,
|
||||||
|
state,
|
||||||
|
dispatch,
|
||||||
|
moderationOpts,
|
||||||
|
}: {
|
||||||
|
generator: GeneratorView
|
||||||
|
state: WizardState
|
||||||
|
dispatch: (action: WizardAction) => void
|
||||||
|
moderationOpts: ModerationOpts
|
||||||
|
}) {
|
||||||
|
const isDiscover = generator.uri === DISCOVER_FEED_URI
|
||||||
|
const included = isDiscover || state.feeds.some(f => f.uri === generator.uri)
|
||||||
|
const disabled = isDiscover || (!included && state.feeds.length >= 3)
|
||||||
|
const moderationUi = moderateFeedGenerator(generator, moderationOpts).ui(
|
||||||
|
'avatar',
|
||||||
|
)
|
||||||
|
|
||||||
|
const onPress = () => {
|
||||||
|
if (disabled) return
|
||||||
|
|
||||||
|
Keyboard.dismiss()
|
||||||
|
if (included) {
|
||||||
|
dispatch({type: 'RemoveFeed', feedUri: generator.uri})
|
||||||
|
} else {
|
||||||
|
dispatch({type: 'AddFeed', feed: generator})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WizardListCard
|
||||||
|
type="algo"
|
||||||
|
displayName={sanitizeDisplayName(generator.displayName)}
|
||||||
|
subtitle={`Feed by @${sanitizeHandle(generator.creator.handle)}`}
|
||||||
|
onPress={onPress}
|
||||||
|
avatar={generator.avatar}
|
||||||
|
included={included}
|
||||||
|
disabled={disabled}
|
||||||
|
moderationUi={moderationUi}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import {Keyboard, Pressable, View} from 'react-native'
|
|
||||||
import {AppBskyActorDefs} from '@atproto/api'
|
|
||||||
import {msg} from '@lingui/macro'
|
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
|
|
||||||
import {isWeb} from 'platform/detection'
|
|
||||||
import {useSession} from 'state/session'
|
|
||||||
import {UserAvatar} from 'view/com/util/UserAvatar'
|
|
||||||
import {WizardAction, WizardState} from '#/screens/StarterPack/Wizard/State'
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
|
||||||
import * as Toggle from '#/components/forms/Toggle'
|
|
||||||
import {Checkbox} from '#/components/forms/Toggle'
|
|
||||||
import {Text} from '#/components/Typography'
|
|
||||||
|
|
||||||
export function WizardProfileCard({
|
|
||||||
state,
|
|
||||||
dispatch,
|
|
||||||
profile,
|
|
||||||
}: {
|
|
||||||
state: WizardState
|
|
||||||
dispatch: (action: WizardAction) => void
|
|
||||||
profile: AppBskyActorDefs.ProfileViewBasic
|
|
||||||
}) {
|
|
||||||
const {_} = useLingui()
|
|
||||||
const t = useTheme()
|
|
||||||
const {currentAccount} = useSession()
|
|
||||||
|
|
||||||
const includesProfile = state.profiles.some(p => p.did === profile.did)
|
|
||||||
const isMe = profile.did === currentAccount?.did
|
|
||||||
const isDisabled = isMe || state.profiles.length >= 50
|
|
||||||
|
|
||||||
const onPressAddRemove = () => {
|
|
||||||
if (isDisabled) return
|
|
||||||
|
|
||||||
Keyboard.dismiss()
|
|
||||||
if (profile.did === currentAccount?.did) return
|
|
||||||
|
|
||||||
if (!includesProfile) {
|
|
||||||
dispatch({type: 'AddProfile', profile})
|
|
||||||
} else {
|
|
||||||
dispatch({type: 'RemoveProfile', profileDid: profile.did})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Pressable
|
|
||||||
accessibilityRole="button"
|
|
||||||
style={[
|
|
||||||
a.flex_row,
|
|
||||||
a.align_center,
|
|
||||||
a.px_lg,
|
|
||||||
a.py_sm,
|
|
||||||
a.gap_md,
|
|
||||||
a.border_b,
|
|
||||||
t.atoms.border_contrast_low,
|
|
||||||
// @ts-expect-error web only
|
|
||||||
isWeb && {
|
|
||||||
cursor: 'default',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
onPress={onPressAddRemove}>
|
|
||||||
<UserAvatar size={45} avatar={profile?.avatar} />
|
|
||||||
<View style={[a.flex_1]}>
|
|
||||||
<Text style={[a.flex_1, a.font_bold, a.text_md]} numberOfLines={1}>
|
|
||||||
{profile?.displayName || profile?.handle}
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
style={[a.flex_1, t.atoms.text_contrast_medium]}
|
|
||||||
numberOfLines={1}>
|
|
||||||
@{profile?.handle}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<Toggle.Item
|
|
||||||
name={_(msg`Person toggle`)}
|
|
||||||
label={
|
|
||||||
includesProfile
|
|
||||||
? _(
|
|
||||||
msg`Remove ${
|
|
||||||
profile.displayName || profile.handle
|
|
||||||
} from starter pack`,
|
|
||||||
)
|
|
||||||
: _(
|
|
||||||
msg`Add ${
|
|
||||||
profile.displayName || profile.handle
|
|
||||||
} to starter pack`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
value={includesProfile}
|
|
||||||
disabled={isDisabled}
|
|
||||||
onChange={onPressAddRemove}>
|
|
||||||
<Checkbox />
|
|
||||||
</Toggle.Item>
|
|
||||||
</Pressable>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
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 {KeyboardAwareScrollView} from 'react-native-keyboard-controller'
|
||||||
|
import {ModerationOpts} 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 debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
|
|
||||||
@@ -14,13 +15,13 @@ import {useWizardState} from '#/screens/StarterPack/Wizard/State'
|
|||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {ScreenTransition} from '#/components/StarterPack/Wizard/ScreenTransition'
|
import {ScreenTransition} from '#/components/StarterPack/Wizard/ScreenTransition'
|
||||||
import {WizardFeedCard} from '#/components/StarterPack/Wizard/WizardFeedCard'
|
import {WizardFeedCard} from '#/components/StarterPack/Wizard/WizardListCard'
|
||||||
|
|
||||||
function keyExtractor(item: GeneratorView) {
|
function keyExtractor(item: GeneratorView) {
|
||||||
return item.uri
|
return item.uri
|
||||||
}
|
}
|
||||||
|
|
||||||
export function StepFeeds() {
|
export function StepFeeds({moderationOpts}: {moderationOpts: ModerationOpts}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const [state, dispatch] = useWizardState()
|
const [state, dispatch] = useWizardState()
|
||||||
const [query, setQuery] = useState('')
|
const [query, setQuery] = useState('')
|
||||||
@@ -52,7 +53,14 @@ export function StepFeeds() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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}
|
||||||
|
moderationOpts={moderationOpts}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
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 {KeyboardAwareScrollView} from 'react-native-keyboard-controller'
|
||||||
import {AppBskyActorDefs} from '@atproto/api'
|
import {AppBskyActorDefs, ModerationOpts} from '@atproto/api'
|
||||||
|
|
||||||
import {useActorAutocompleteQuery} from 'state/queries/actor-autocomplete'
|
import {useActorAutocompleteQuery} from 'state/queries/actor-autocomplete'
|
||||||
import {useActorSearch} from 'state/queries/actor-search'
|
import {useActorSearch} from 'state/queries/actor-search'
|
||||||
@@ -11,13 +11,17 @@ import {useWizardState} from '#/screens/StarterPack/Wizard/State'
|
|||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {ScreenTransition} from '#/components/StarterPack/Wizard/ScreenTransition'
|
import {ScreenTransition} from '#/components/StarterPack/Wizard/ScreenTransition'
|
||||||
import {WizardProfileCard} from '#/components/StarterPack/Wizard/WizardProfileCard'
|
import {WizardProfileCard} from '#/components/StarterPack/Wizard/WizardListCard'
|
||||||
|
|
||||||
function keyExtractor(item: AppBskyActorDefs.ProfileViewBasic) {
|
function keyExtractor(item: AppBskyActorDefs.ProfileViewBasic) {
|
||||||
return item.did
|
return item.did
|
||||||
}
|
}
|
||||||
|
|
||||||
export function StepProfiles() {
|
export function StepProfiles({
|
||||||
|
moderationOpts,
|
||||||
|
}: {
|
||||||
|
moderationOpts: ModerationOpts
|
||||||
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const [state, dispatch] = useWizardState()
|
const [state, dispatch] = useWizardState()
|
||||||
const [query, setQuery] = useState('')
|
const [query, setQuery] = useState('')
|
||||||
@@ -32,7 +36,12 @@ export function StepProfiles() {
|
|||||||
item,
|
item,
|
||||||
}: ListRenderItemInfo<AppBskyActorDefs.ProfileViewBasic>) => {
|
}: ListRenderItemInfo<AppBskyActorDefs.ProfileViewBasic>) => {
|
||||||
return (
|
return (
|
||||||
<WizardProfileCard profile={item} state={state} dispatch={dispatch} />
|
<WizardProfileCard
|
||||||
|
profile={item}
|
||||||
|
state={state}
|
||||||
|
dispatch={dispatch}
|
||||||
|
moderationOpts={moderationOpts}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
AppBskyGraphDefs,
|
AppBskyGraphDefs,
|
||||||
AppBskyGraphStarterpack,
|
AppBskyGraphStarterpack,
|
||||||
AtUri,
|
AtUri,
|
||||||
|
ModerationOpts,
|
||||||
} from '@atproto/api'
|
} 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 {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
@@ -24,8 +25,11 @@ import {HITSLOP_10} from 'lib/constants'
|
|||||||
import {createStarterPackList} from 'lib/generate-starterpack'
|
import {createStarterPackList} from 'lib/generate-starterpack'
|
||||||
import {CommonNavigatorParams, NavigationProp} from 'lib/routes/types'
|
import {CommonNavigatorParams, NavigationProp} from 'lib/routes/types'
|
||||||
import {logEvent} from 'lib/statsig/statsig'
|
import {logEvent} from 'lib/statsig/statsig'
|
||||||
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
|
import {sanitizeHandle} from 'lib/strings/handles'
|
||||||
import {enforceLen} from 'lib/strings/helpers'
|
import {enforceLen} from 'lib/strings/helpers'
|
||||||
import {isAndroid, isNative, isWeb} from 'platform/detection'
|
import {isAndroid, isNative, isWeb} from 'platform/detection'
|
||||||
|
import {useModerationOpts} from 'state/preferences/moderation-opts'
|
||||||
import {invalidateActorStarterPacksQuery} from 'state/queries/actor-starter-packs'
|
import {invalidateActorStarterPacksQuery} from 'state/queries/actor-starter-packs'
|
||||||
import {
|
import {
|
||||||
invalidateListMembersQuery,
|
invalidateListMembersQuery,
|
||||||
@@ -61,6 +65,7 @@ export function Wizard({
|
|||||||
}: NativeStackScreenProps<CommonNavigatorParams, 'StarterPackWizard'>) {
|
}: NativeStackScreenProps<CommonNavigatorParams, 'StarterPackWizard'>) {
|
||||||
const {name, rkey} = route.params ?? {}
|
const {name, rkey} = route.params ?? {}
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
|
const moderationOpts = useModerationOpts()
|
||||||
|
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
|
||||||
@@ -91,7 +96,10 @@ export function Wizard({
|
|||||||
} = useProfileQuery({did: currentAccount?.did})
|
} = useProfileQuery({did: currentAccount?.did})
|
||||||
|
|
||||||
const isEdit = Boolean(name && rkey)
|
const isEdit = Boolean(name && rkey)
|
||||||
const isReady = (!isEdit || (isEdit && starterPack && listItems)) && profile
|
const isReady =
|
||||||
|
(!isEdit || (isEdit && starterPack && listItems)) &&
|
||||||
|
profile &&
|
||||||
|
moderationOpts
|
||||||
|
|
||||||
if (!isReady) {
|
if (!isReady) {
|
||||||
return (
|
return (
|
||||||
@@ -130,6 +138,7 @@ export function Wizard({
|
|||||||
}
|
}
|
||||||
listItems={listItems}
|
listItems={listItems}
|
||||||
listUri={listUri}
|
listUri={listUri}
|
||||||
|
moderationOpts={moderationOpts}
|
||||||
/>
|
/>
|
||||||
</Provider>
|
</Provider>
|
||||||
)
|
)
|
||||||
@@ -141,12 +150,14 @@ function WizardInner({
|
|||||||
createdAt: initialCreatedAt,
|
createdAt: initialCreatedAt,
|
||||||
listUri: initialListUri,
|
listUri: initialListUri,
|
||||||
listItems: initialListItems,
|
listItems: initialListItems,
|
||||||
|
moderationOpts,
|
||||||
}: {
|
}: {
|
||||||
did?: string
|
did?: string
|
||||||
rkey?: string
|
rkey?: string
|
||||||
createdAt?: string
|
createdAt?: string
|
||||||
listUri?: string
|
listUri?: string
|
||||||
listItems?: AppBskyGraphDefs.ListItemView[]
|
listItems?: AppBskyGraphDefs.ListItemView[]
|
||||||
|
moderationOpts: ModerationOpts
|
||||||
}) {
|
}) {
|
||||||
const navigation = useNavigation<NavigationProp>()
|
const navigation = useNavigation<NavigationProp>()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
@@ -445,11 +456,21 @@ function WizardInner({
|
|||||||
<Container
|
<Container
|
||||||
showDeleteBtn={Boolean(did && rkey)}
|
showDeleteBtn={Boolean(did && rkey)}
|
||||||
deleteStarterPack={deleteStarterPack}>
|
deleteStarterPack={deleteStarterPack}>
|
||||||
<StepView />
|
{state.currentStep === 'Details' ? (
|
||||||
|
<StepDetails />
|
||||||
|
) : state.currentStep === 'Profiles' ? (
|
||||||
|
<StepProfiles moderationOpts={moderationOpts} />
|
||||||
|
) : state.currentStep === 'Feeds' ? (
|
||||||
|
<StepFeeds moderationOpts={moderationOpts} />
|
||||||
|
) : null}
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
{state.currentStep !== 'Details' && (
|
{state.currentStep !== 'Details' && (
|
||||||
<Footer onNext={onNext} nextBtnText={currUiStrings.nextBtn} />
|
<Footer
|
||||||
|
onNext={onNext}
|
||||||
|
nextBtnText={currUiStrings.nextBtn}
|
||||||
|
moderationOpts={moderationOpts}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</CenteredView>
|
</CenteredView>
|
||||||
)
|
)
|
||||||
@@ -530,9 +551,11 @@ function Container({
|
|||||||
function Footer({
|
function Footer({
|
||||||
onNext,
|
onNext,
|
||||||
nextBtnText,
|
nextBtnText,
|
||||||
|
moderationOpts,
|
||||||
}: {
|
}: {
|
||||||
onNext: () => void
|
onNext: () => void
|
||||||
nextBtnText: string
|
nextBtnText: string
|
||||||
|
moderationOpts: ModerationOpts
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
@@ -694,6 +717,7 @@ function Footer({
|
|||||||
control={editDialogControl}
|
control={editDialogControl}
|
||||||
state={state}
|
state={state}
|
||||||
dispatch={dispatch}
|
dispatch={dispatch}
|
||||||
|
moderationOpts={moderationOpts}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
@@ -701,23 +725,9 @@ function Footer({
|
|||||||
|
|
||||||
function getName(item: AppBskyActorDefs.ProfileViewBasic | GeneratorView) {
|
function getName(item: AppBskyActorDefs.ProfileViewBasic | GeneratorView) {
|
||||||
if (typeof item.displayName === 'string') {
|
if (typeof item.displayName === 'string') {
|
||||||
return enforceLen(item.displayName, 16, true)
|
return enforceLen(sanitizeDisplayName(item.displayName), 16, true)
|
||||||
} else if (typeof item.handle === 'string') {
|
} else if (typeof item.handle === 'string') {
|
||||||
return enforceLen(item.handle, 16, true)
|
return enforceLen(sanitizeHandle(item.handle), 16, true)
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
function StepView() {
|
|
||||||
const [state] = useWizardState()
|
|
||||||
|
|
||||||
if (state.currentStep === 'Details') {
|
|
||||||
return <StepDetails />
|
|
||||||
}
|
|
||||||
if (state.currentStep === 'Profiles') {
|
|
||||||
return <StepProfiles />
|
|
||||||
}
|
|
||||||
if (state.currentStep === 'Feeds') {
|
|
||||||
return <StepFeeds />
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user