diff --git a/src/screens/Profile/Header/ProfileHeaderModerator.tsx b/src/screens/Profile/Header/ProfileHeaderModerator.tsx index 9c5d36a58f..6a054f0be3 100644 --- a/src/screens/Profile/Header/ProfileHeaderModerator.tsx +++ b/src/screens/Profile/Header/ProfileHeaderModerator.tsx @@ -2,6 +2,7 @@ import React, {memo, useMemo} from 'react' import {View} from 'react-native' import { AppBskyActorDefs, + AppBskyModerationDefs, ModerationOpts, moderateProfile, RichText as RichTextAPI, @@ -36,6 +37,7 @@ import { interface Props { profile: AppBskyActorDefs.ProfileViewDetailed + modservice: AppBskyModerationDefs.ModServiceViewDetailed descriptionRT: RichTextAPI | null moderationOpts: ModerationOpts hideBackButton?: boolean @@ -44,6 +46,7 @@ interface Props { let ProfileHeaderModerator = ({ profile: profileUnshadowed, + modservice, descriptionRT, moderationOpts, hideBackButton = false, @@ -66,16 +69,18 @@ let ProfileHeaderModerator = ({ const isSubscribed = variables?.subscribe ?? preferences?.moderationOpts.mods.find(mod => mod.did === profile.did) - const modservice = {likeCount: 0} // TODO const {mutateAsync: likeMod, isPending: isLikePending} = useLikeMutation() const {mutateAsync: unlikeMod, isPending: isUnlikePending} = useUnlikeMutation() const [likeUri, setLikeUri] = React.useState( - /* TODO modservice.viewer?.like ||*/ '', + modservice.viewer?.like || '', ) const isLiked = !!likeUri const onToggleLiked = React.useCallback(async () => { + if (!modservice) { + return + } try { Haptics.default() @@ -84,10 +89,9 @@ let ProfileHeaderModerator = ({ track('CustomFeed:Unlike') setLikeUri('') } else { - // TODO - // const res = await likeMod({uri: modservice.uri, cid: modservice.cid}) + const res = await likeMod({uri: modservice.uri, cid: modservice.cid}) track('CustomFeed:Like') - // setLikeUri(res.uri) + setLikeUri(res.uri) } } catch (e: any) { Toast.show( @@ -97,7 +101,7 @@ let ProfileHeaderModerator = ({ ) logger.error(`Failed to toggle labeler like`, {message: e.message}) } - }, [likeUri, isLiked, likeMod, unlikeMod, track, _]) + }, [modservice, likeUri, isLiked, likeMod, unlikeMod, track, _]) const onPressEditProfile = React.useCallback(() => { track('ProfileHeader:EditProfileButtonClicked') diff --git a/src/screens/Profile/Header/ProfileHeaderStandard.tsx b/src/screens/Profile/Header/ProfileHeaderStandard.tsx index e12b259e36..d4c3ff5af4 100644 --- a/src/screens/Profile/Header/ProfileHeaderStandard.tsx +++ b/src/screens/Profile/Header/ProfileHeaderStandard.tsx @@ -28,7 +28,7 @@ import {sanitizeDisplayName} from 'lib/strings/display-names' import {atoms as a, useTheme} from '#/alf' import {Text} from '#/components/Typography' import {InlineLink} from '#/components/Link' -import {Button, ButtonText} from '#/components/Button' +import {Button, ButtonText, ButtonIcon} from '#/components/Button' import * as Toast from '#/view/com/util/Toast' import {ProfileHeaderShell} from './Shell' import {ProfileHeaderDropdownBtn} from './DropdownBtn' @@ -36,6 +36,8 @@ import {ProfileHeaderDisplayName} from './DisplayName' import {ProfileHeaderHandle} from './Handle' import {ProfileHeaderSuggestedFollows} from '#/view/com/profile/ProfileHeaderSuggestedFollows' import {RichText} from 'view/com/util/text/RichText' +import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' +import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' interface Props { profile: AppBskyActorDefs.ProfileViewDetailed @@ -224,7 +226,11 @@ let ProfileHeaderStandard = ({ onPress={ profile.viewer?.following ? onPressUnfollow : onPressFollow } - style={a.rounded_full}> + style={[a.rounded_full, a.gap_xs]}> + {profile.viewer?.following ? ( Following diff --git a/src/screens/Profile/Header/index.tsx b/src/screens/Profile/Header/index.tsx index ea39d9c44f..70f655e46a 100644 --- a/src/screens/Profile/Header/index.tsx +++ b/src/screens/Profile/Header/index.tsx @@ -2,6 +2,7 @@ import React, {memo} from 'react' import {StyleSheet, View} from 'react-native' import { AppBskyActorDefs, + AppBskyModerationDefs, ModerationOpts, RichText as RichTextAPI, } from '@atproto/api' @@ -33,6 +34,7 @@ export {ProfileHeaderLoading} interface Props { profile: AppBskyActorDefs.ProfileViewDetailed + modservice: AppBskyModerationDefs.ModServiceViewDetailed | undefined descriptionRT: RichTextAPI | null moderationOpts: ModerationOpts hideBackButton?: boolean @@ -41,7 +43,10 @@ interface Props { let ProfileHeader = (props: Props): React.ReactNode => { if (props.profile.associated?.modservice) { - return + if (!props.modservice) { + return + } + return } return } diff --git a/src/screens/Profile/FiltersSection.tsx b/src/screens/Profile/Sections/ContentFilters.tsx similarity index 82% rename from src/screens/Profile/FiltersSection.tsx rename to src/screens/Profile/Sections/ContentFilters.tsx index 726d50267c..67a3bd1b68 100644 --- a/src/screens/Profile/FiltersSection.tsx +++ b/src/screens/Profile/Sections/ContentFilters.tsx @@ -1,6 +1,6 @@ import React from 'react' import {View} from 'react-native' -import {AppBskyModerationDefs, AppBskyActorDefs} from '@atproto/api' +import {AppBskyModerationDefs, ModerationOpts} from '@atproto/api' import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useSafeAreaFrame} from 'react-native-safe-area-context' @@ -11,14 +11,7 @@ import {Haptics} from '#/lib/haptics' import {useAnalytics} from '#/lib/analytics/analytics' import {CenteredView, ScrollView} from '#/view/com/util/Views' import {logger} from '#/logger' -import { - useModServiceInfoQuery, - useModServiceEnableMutation, -} from '#/state/queries/modservice' -import { - UsePreferencesQueryResponse, - usePreferencesQuery, -} from '#/state/queries/preferences' +import {useModServiceEnableMutation} from '#/state/queries/modservice' import {useSession} from '#/state/session' import {useLikeMutation, useUnlikeMutation} from '#/state/queries/like' @@ -33,28 +26,21 @@ import * as Toggle from '#/components/forms/Toggle' import {ErrorState} from '#/screens/ProfileModerationService/ErrorState' import {PreferenceRow} from '#/screens/ProfileModerationService/PreferenceRow' -export function ProfileFiltersSection({ - profile, +export function ProfileContentFiltersSection({ + modServiceQuery, + moderationOpts, }: { - profile: AppBskyActorDefs.ProfileViewDetailed + modServiceQuery: { + data: AppBskyModerationDefs.ModServiceViewDetailed | undefined + isLoading: boolean + error: Error | null + } + moderationOpts: ModerationOpts }) { const t = useTheme() const {_} = useLingui() const {height: minHeight} = useSafeAreaFrame() - const { - isLoading: isPreferencesLoading, - error: preferencesError, - data: preferences, - } = usePreferencesQuery() - const { - isLoading: isModServiceLoading, - error: modServiceError, - data: modservice, - } = useModServiceInfoQuery({did: profile.did}) - - const isLoading = isPreferencesLoading || isModServiceLoading - const error = preferencesError || modServiceError - + const {isLoading, error, data: modservice} = modServiceQuery return ( - ) : error || !(preferences && modservice) ? ( + ) : error || !modservice ? ( ) : ( - )} @@ -89,11 +75,11 @@ export function ProfileFiltersSection({ ) } -export function ProfileFiltersSectionInner({ - preferences, +export function ProfileContentFiltersSectionInner({ + moderationOpts, modservice, }: { - preferences: UsePreferencesQueryResponse + moderationOpts: ModerationOpts modservice: AppBskyModerationDefs.ModServiceViewDetailed }) { const t = useTheme() @@ -119,16 +105,14 @@ export function ProfileFiltersSectionInner({ ) }, [modservice.policies.labelValues]) const modservicePreferences = React.useMemo(() => { - return preferences.moderationOpts.mods.find( - p => p.did === modservice.creator.did, - ) - }, [modservice.creator.did, preferences.moderationOpts.mods]) - const isSubscribed = preferences.moderationOpts.mods.find( + return moderationOpts.mods.find(p => p.did === modservice.creator.did) + }, [modservice.creator.did, moderationOpts.mods]) + const isSubscribed = moderationOpts.mods.find( mod => mod.did === modservice.creator.did, ) const isEnabled = Boolean( enabledVariables?.enabled ?? - preferences.moderationOpts.mods.find( + moderationOpts.mods.find( mod => mod.did === modservice.creator.did && mod.enabled, ), ) diff --git a/src/state/queries/modservice.ts b/src/state/queries/modservice.ts index 4a4ebf674e..3a2e708cc7 100644 --- a/src/state/queries/modservice.ts +++ b/src/state/queries/modservice.ts @@ -15,9 +15,15 @@ export const modServicesDetailedInfoQueryKey = (dids: string[]) => [ dids, ] -export function useModServiceInfoQuery({did}: {did?: string}) { +export function useModServiceInfoQuery({ + did, + enabled, +}: { + did?: string + enabled?: boolean +}) { return useQuery({ - enabled: !!did, + enabled: !!did && enabled !== false, queryKey: modServiceInfoQueryKey(did as string), queryFn: async () => { const res = await getAgent().app.bsky.moderation.getService({ diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index b208062c61..5c13162930 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -36,6 +36,7 @@ import {useProfileShadow} from '#/state/cache/profile-shadow' import {useSession, getAgent} from '#/state/session' import {useModerationOpts} from '#/state/queries/preferences' import {useProfileExtraInfoQuery} from '#/state/queries/profile-extra-info' +import {useModServiceInfoQuery} from '#/state/queries/modservice' import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' import {useSetDrawerSwipeDisabled, useSetMinimalShellMode} from '#/state/shell' import {cleanError} from '#/lib/strings/errors' @@ -52,7 +53,7 @@ import {isInvalidHandle} from '#/lib/strings/handles' import {useTheme, atoms as a} from '#/alf' import * as ModerationServiceCard from '#/components/ModerationServiceCard' import {RaisingHande4Finger_Stroke2_Corner0_Rounded as RaisingHand} from '#/components/icons/RaisingHand' -import {ProfileFiltersSection} from '#/screens/Profile/FiltersSection' +import {ProfileContentFiltersSection} from '#/screens/Profile/Sections/ContentFilters' import {ProfileHeader as ProfileHeaderV2} from '#/screens/Profile/Header' interface SectionRef { @@ -449,6 +450,10 @@ function ProfileScreenLoadedV2({ const setMinimalShellMode = useSetMinimalShellMode() const {openComposer} = useComposerControls() const {screen, track} = useAnalytics() + const modServiceQuery = useModServiceInfoQuery({ + did: profile.did, + enabled: !!profile.associated?.modservice, + }) const [currentPage, setCurrentPage] = React.useState(0) const {_} = useLingui() const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled() @@ -616,6 +621,7 @@ function ProfileScreenLoadedV2({ return ( {showFiltersTab ? ({headerHeight, isFocused, scrollElRef}) => ( - - ( - - {ctx => ( - - - - - - - )} - - )} - /> - - ) -} - function useRichText(text: string): [RichTextAPI, boolean] { const [prevText, setPrevText] = React.useState(text) const [rawRT, setRawRT] = React.useState(() => new RichTextAPI({text}))