diff --git a/src/components/LikesDialog.tsx b/src/components/LikesDialog.tsx
deleted file mode 100644
index cb000b4337..0000000000
--- a/src/components/LikesDialog.tsx
+++ /dev/null
@@ -1,129 +0,0 @@
-import {useCallback, useMemo} from 'react'
-import {ActivityIndicator, FlatList, View} from 'react-native'
-import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api'
-import {msg, Trans} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-
-import {cleanError} from '#/lib/strings/errors'
-import {logger} from '#/logger'
-import {useLikedByQuery} from '#/state/queries/post-liked-by'
-import {useResolveUriQuery} from '#/state/queries/resolve-uri'
-import {ProfileCardWithFollowBtn} from '#/view/com/profile/ProfileCard'
-import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
-import {atoms as a, useTheme} from '#/alf'
-import * as Dialog from '#/components/Dialog'
-import {Loader} from '#/components/Loader'
-import {Text} from '#/components/Typography'
-
-interface LikesDialogProps {
- control: Dialog.DialogOuterProps['control']
- uri: string
-}
-
-export function LikesDialog(props: LikesDialogProps) {
- return (
-
-
-
-
- )
-}
-
-export function LikesDialogInner({control, uri}: LikesDialogProps) {
- const {_} = useLingui()
- const t = useTheme()
-
- const {
- data: resolvedUri,
- error: resolveError,
- isFetched: hasFetchedResolvedUri,
- } = useResolveUriQuery(uri)
- const {
- data,
- isFetching: isFetchingLikedBy,
- isFetched: hasFetchedLikedBy,
- isFetchingNextPage,
- hasNextPage,
- fetchNextPage,
- isError,
- error: likedByError,
- } = useLikedByQuery(resolvedUri?.uri)
-
- const isLoading = !hasFetchedResolvedUri || !hasFetchedLikedBy
- const likes = useMemo(() => {
- if (data?.pages) {
- return data.pages.flatMap(page => page.likes)
- }
- return []
- }, [data])
-
- const onEndReached = useCallback(async () => {
- if (isFetchingLikedBy || !hasNextPage || isError) return
- try {
- await fetchNextPage()
- } catch (err) {
- logger.error('Failed to load more likes', {message: err})
- }
- }, [isFetchingLikedBy, hasNextPage, isError, fetchNextPage])
-
- const renderItem = useCallback(
- ({item}: {item: GetLikes.Like}) => {
- return (
- control.close()}
- />
- )
- },
- [control],
- )
-
- return (
-
-
- Liked by
-
-
- {isLoading ? (
-
-
-
- ) : resolveError || likedByError || !data ? (
-
- ) : likes.length === 0 ? (
-
-
-
- Nobody has liked this yet. Maybe you should be the first!
-
-
-
- ) : (
- item.actor.did}
- onEndReached={onEndReached}
- renderItem={renderItem}
- initialNumToRender={15}
- ListFooterComponent={
-
- }
- />
- )}
-
-
-
- )
-}
-
-function ListFooterComponent({isFetching}: {isFetching: boolean}) {
- if (isFetching) {
- return (
-
-
-
- )
- }
- return null
-}
diff --git a/src/components/ProfileCard.tsx b/src/components/ProfileCard.tsx
index beb09cdc74..394ff99462 100644
--- a/src/components/ProfileCard.tsx
+++ b/src/components/ProfileCard.tsx
@@ -8,15 +8,15 @@ import {
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
+import {getModerationCauseKey} from '#/lib/moderation'
import {type LogEvents} from '#/lib/statsig/statsig'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {useProfileFollowMutationQueue} from '#/state/queries/profile'
import {useSession} from '#/state/session'
-import {ProfileCardPills} from '#/view/com/profile/ProfileCard'
import * as Toast from '#/view/com/util/Toast'
-import {UserAvatar} from '#/view/com/util/UserAvatar'
+import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
import {atoms as a, useTheme} from '#/alf'
import {
Button,
@@ -27,6 +27,7 @@ import {
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {Link as InternalLink, type LinkProps} from '#/components/Link'
+import * as Pills from '#/components/Pills'
import {RichText} from '#/components/RichText'
import {Text} from '#/components/Typography'
import type * as bsky from '#/types/bsky'
@@ -35,13 +36,15 @@ export function Default({
profile,
moderationOpts,
logContext = 'ProfileCard',
+ testID,
}: {
profile: bsky.profile.AnyProfileView
moderationOpts: ModerationOpts
logContext?: 'ProfileCard' | 'StarterPackProfilesList'
+ testID?: string
}) {
return (
-
+
@@ -74,10 +75,7 @@ export function Card({
/>
-
+
@@ -87,7 +85,7 @@ export function Card({
export function Outer({
children,
}: {
- children: React.ReactElement | React.ReactElement[]
+ children: React.ReactNode | React.ReactNode[]
}) {
return {children}
}
@@ -95,7 +93,7 @@ export function Outer({
export function Header({
children,
}: {
- children: React.ReactElement | React.ReactElement[]
+ children: React.ReactNode | React.ReactNode[]
}) {
return {children}
}
@@ -137,10 +135,9 @@ export function Avatar({
const moderation = moderateProfile(profile, moderationOpts)
return (
-
)
@@ -415,3 +412,31 @@ export function FollowButtonInner({
)
}
+
+export function Labels({
+ profile,
+ moderationOpts,
+}: {
+ profile: bsky.profile.AnyProfileView
+ moderationOpts: ModerationOpts
+}) {
+ const moderation = moderateProfile(profile, moderationOpts)
+ const modui = moderation.ui('profileList')
+ const followedBy = profile.viewer?.followedBy
+
+ if (!followedBy && !modui.inform && !modui.alert) {
+ return null
+ }
+
+ return (
+
+ {followedBy && }
+ {modui.alerts.map(alert => (
+
+ ))}
+ {modui.informs.map(inform => (
+
+ ))}
+
+ )
+}
diff --git a/src/screens/Search/SearchResults.tsx b/src/screens/Search/SearchResults.tsx
index bb51d2deb2..6b7a582d54 100644
--- a/src/screens/Search/SearchResults.tsx
+++ b/src/screens/Search/SearchResults.tsx
@@ -275,9 +275,7 @@ let SearchScreenUserResults = ({
{results.length ? (
(
-
- )}
+ renderItem={({item}) => }
keyExtractor={item => item.did}
desktopFixedHeight
contentContainerStyle={{paddingBottom: 100}}
diff --git a/src/view/com/lists/ListMembers.tsx b/src/view/com/lists/ListMembers.tsx
index da32c2d483..dc18cbe5db 100644
--- a/src/view/com/lists/ListMembers.tsx
+++ b/src/view/com/lists/ListMembers.tsx
@@ -1,22 +1,23 @@
import React, {useCallback} from 'react'
import {Dimensions, type StyleProp, View, type ViewStyle} from 'react-native'
import {type AppBskyGraphDefs} from '@atproto/api'
-import {msg} from '@lingui/macro'
+import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
-import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {cleanError} from '#/lib/strings/errors'
import {logger} from '#/logger'
import {useModalControls} from '#/state/modals'
+import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useListMembersQuery} from '#/state/queries/list-members'
import {useSession} from '#/state/session'
-import {ProfileCard} from '#/view/com/profile/ProfileCard'
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
-import {Button} from '#/view/com/util/forms/Button'
import {List, type ListRef} from '#/view/com/util/List'
import {ProfileCardFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn'
+import {atoms as a, useTheme} from '#/alf'
+import {Button, ButtonText} from '#/components/Button'
import {ListFooter} from '#/components/Lists'
+import * as ProfileCard from '#/components/ProfileCard'
import type * as bsky from '#/types/bsky'
const LOADING_ITEM = {_reactKey: '__loading__'}
@@ -47,11 +48,12 @@ export function ListMembers({
headerOffset?: number
desktopFixedHeightOffset?: number
}) {
+ const t = useTheme()
const {_} = useLingui()
const [isRefreshing, setIsRefreshing] = React.useState(false)
- const {isMobile} = useWebMediaQueries()
const {openModal} = useModalControls()
const {currentAccount} = useSession()
+ const moderationOpts = useModerationOpts()
const {
data,
@@ -131,23 +133,6 @@ export function ListMembers({
// rendering
// =
- const renderMemberButton = React.useCallback(
- (profile: bsky.profile.AnyProfileView) => {
- if (!isOwner) {
- return null
- }
- return (
-