diff --git a/src/view/com/util/post-ctrls/SubmitButton.tsx b/src/view/com/util/post-ctrls/SubmitButton.tsx index df641b5373..de145222ce 100644 --- a/src/view/com/util/post-ctrls/SubmitButton.tsx +++ b/src/view/com/util/post-ctrls/SubmitButton.tsx @@ -1,35 +1,27 @@ import React from 'react' import {TextInput, View} from 'react-native' -import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api' -import {msg, Plural, Trans} from '@lingui/macro' +import {AppBskyFeedDefs} from '@atproto/api' +import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {sanitizeDisplayName} from '#/lib/strings/display-names' -import {sanitizeHandle} from '#/lib/strings/handles' import {isWeb} from '#/platform/detection' -import {useModerationOpts} from '#/state/preferences/moderation-opts' -import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete' -import {useProfilesQuery} from '#/state/queries/profile' import {ListMethods} from '#/view/com/util/List' import {UserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, native, useTheme, web} from '#/alf' -import {Button, ButtonIcon} from '#/components/Button' +import {Button, ButtonText} from '#/components/Button' +import {useFeedsAutocomplete} from '#/components/Composer/FeedsSelector/useFeedsAutocomplete' import * as Dialog from '#/components/Dialog' import * as Toggle from '#/components/forms/Toggle' import {useInteractionState} from '#/components/hooks/useInteractionState' import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2' -import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' import {Text} from '#/components/Typography' -const AVI_SIZE = 30 -const AVI_BORDER = 1 - type Item = | { - type: 'profile' + type: 'feed' key: string checked: boolean - profile: AppBskyActorDefs.ProfileView + feed: AppBskyFeedDefs.GeneratorView } | { type: 'empty' @@ -45,306 +37,79 @@ type Item = key: string } -export function UserSelectButton({ - dids, - onChangeDids, -}: { - dids: string[] - onChangeDids: (dids: string[]) => void -}) { - const t = useTheme() - const {_} = useLingui() - const control = Dialog.useDialogControl() - const {data: profiles} = useProfilesQuery({ - handles: dids, - }) - const moderationOpts = useModerationOpts() - const slice = - profiles?.profiles?.slice(0, 3).map(f => { - if (!moderationOpts) { - return { - profile: { - ...f, - displayName: f.displayName || f.handle, - }, - moderation: null, - } - } - const moderation = moderateProfile(f, moderationOpts) - return { - profile: { - ...f, - displayName: sanitizeDisplayName( - f.displayName || f.handle, - moderation.ui('displayName'), - ), - }, - moderation, - } - }) || [] - const serverCount = dids.length - const textStyle = [a.text_sm] - - return ( - <> - - - - - - - - ) -} - export function FeedSelectDialog({ control, - profiles, - dids, - onChangeDids, }: { control: Dialog.DialogOuterProps['control'] - profiles: AppBskyActorDefs.ProfileView[] - dids: string[] - onChangeDids: (dids: string[]) => void }) { const t = useTheme() const {_} = useLingui() - const moderationOpts = useModerationOpts() const listRef = React.useRef(null) const inputRef = React.useRef(null) - const [searchText, setSearchText] = React.useState('') + const [uris, setUris] = React.useState([]) const { - data: results, - isError, - isFetching, - } = useActorAutocompleteQuery(searchText, true, 12) + query: searchText, + suggestions: results, + feeds, + setQuery: setSearchText, + } = useFeedsAutocomplete() - const onToggleUser = React.useCallback( - (did: string, checked: boolean) => { + const onToggleFeed = React.useCallback( + (uri: string, checked: boolean) => { if (checked) { - onChangeDids(Array.from(new Set([did, ...dids]))) + setUris(Array.from(new Set([uri, ...uris]))) } else { - onChangeDids(dids.filter(d => d !== did)) + setUris(uris.filter(u => u !== uri)) } }, - [dids, onChangeDids], + [uris], ) const items = React.useMemo(() => { let _items: Item[] = [] - if (isError) { - _items.push({ - type: 'empty', - key: 'empty', - message: _(msg`We're having network issues, try again`), - }) - } else if (searchText.length) { + if (searchText.length) { if (results?.length) { - for (const profile of results) { + for (const feed of results) { _items.push({ - type: 'profile', - key: profile.did, - checked: dids.includes(profile.did), - profile, + type: 'feed', + key: feed.uri, + checked: uris.includes(feed.uri), + feed, }) } - - // _items = _items.sort(item => { - // // @ts-ignore - // return item.enabled ? -1 : 1 - // }) } } else { - if (profiles.length) { - for (const profile of profiles) { + if (feeds?.length) { + for (const feed of feeds) { _items.push({ - type: 'profile', - key: profile.did, - checked: dids.includes(profile.did), - profile, + type: 'feed', + key: feed.uri, + checked: uris.includes(feed.uri), + feed, }) } - - // _items = _items.sort(item => { - // // @ts-ignore - // return item.checked ? -1 : 1 - // }) - } else { - const placeholders: Item[] = Array(10) - .fill(0) - .map((__, i) => ({ - type: 'placeholder', - key: i + '', - })) - _items.push(...placeholders) } } - return _items - }, [_, dids, profiles, searchText, results, isError]) + }, [results, uris, feeds, searchText]) - if (searchText && !isFetching && !items.length && !isError) { + if (searchText && !items.length) { items.push({type: 'empty', key: 'empty', message: _(msg`No results`)}) } const renderItems = React.useCallback( ({item}: {item: Item}) => { switch (item.type) { - case 'profile': { + case 'feed': { return ( - ) } @@ -358,7 +123,7 @@ export function FeedSelectDialog({ return null } }, - [moderationOpts, onToggleUser], + [onToggleFeed], ) React.useLayoutEffect(() => { @@ -396,21 +161,29 @@ export function FeedSelectDialog({ /> - {isWeb && ( - - )} + ) - }, [t.atoms.border_contrast_low, t.atoms.bg, _, searchText, control]) + }, [ + t.atoms.border_contrast_low, + t.atoms.bg, + uris, + _, + searchText, + control, + setSearchText, + ]) return ( void + feed: AppBskyFeedDefs.GeneratorView + onToggle: (uri: string, checked: boolean) => void }) { const t = useTheme() const {_} = useLingui() - const moderation = moderateProfile(profile, moderationOpts) - const handle = sanitizeHandle(profile.handle, '@') - const displayName = sanitizeDisplayName( - profile.displayName || sanitizeHandle(profile.handle), - moderation.ui('displayName'), - ) + const displayName = feed.displayName const handleOnPress = React.useCallback( (selected: boolean) => { - onToggle(profile.did, selected) + onToggle(feed.uri, selected) }, - [onToggle, profile.did], + [onToggle, feed.uri], ) return ( {({hovered, pressed, focused}) => ( @@ -479,12 +245,7 @@ function ProfileCard({ ? t.atoms.bg_contrast_50 : t.atoms.bg, ]}> - + - {handle} + by @{feed.creator.handle}