From 5e0ffc091788e1f63a3e9d1f4f1e770ed6361aa9 Mon Sep 17 00:00:00 2001 From: Spence Pope Date: Fri, 20 Feb 2026 11:23:01 -0500 Subject: [PATCH] [APP-1809] add cleanup button for unavailable moderation services (#9901) Co-authored-by: Samuel Newman --- src/screens/Moderation/index.tsx | 61 +++++++++++++++++++++++++++++--- src/state/queries/labeler.ts | 16 +++++++++ 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/screens/Moderation/index.tsx b/src/screens/Moderation/index.tsx index 98abda006b..6f75370511 100644 --- a/src/screens/Moderation/index.tsx +++ b/src/screens/Moderation/index.tsx @@ -5,13 +5,14 @@ import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useFocusEffect} from '@react-navigation/native' -import {getLabelingServiceTitle} from '#/lib/moderation' +import {getLabelingServiceTitle, isAppLabeler} from '#/lib/moderation' import { type CommonNavigatorParams, type NativeStackScreenProps, } from '#/lib/routes/types' import {logger} from '#/logger' import {useIsBirthdateUpdateAllowed} from '#/state/birthdate' +import {useRemoveLabelersMutation} from '#/state/queries/labeler' import { useMyLabelersQuery, usePreferencesQuery, @@ -21,10 +22,10 @@ import { import {isNonConfigurableModerationAuthority} from '#/state/session/additional-moderation-authorities' import {useSetMinimalShellMode} from '#/state/shell' import {atoms as a, useBreakpoints, useTheme, type ViewStyleProp} from '#/alf' -import {Admonition} from '#/components/Admonition' +import * as Admonition from '#/components/Admonition' import {AgeAssuranceAdmonition} from '#/components/ageAssurance/AgeAssuranceAdmonition' import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy' -import {Button} from '#/components/Button' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {useGlobalDialogsControlContext} from '#/components/dialogs/Context' import {Divider} from '#/components/Divider' import * as Toggle from '#/components/forms/Toggle' @@ -42,6 +43,7 @@ import {InlineLinkText, Link} from '#/components/Link' import {ListMaybePlaceholder} from '#/components/Lists' import {Loader} from '#/components/Loader' import {GlobalLabelPreference} from '#/components/moderation/LabelPreference' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {useAgeAssurance} from '#/ageAssurance' import {IS_IOS} from '#/env' @@ -166,10 +168,34 @@ export function ModerationScreenInner({ data: labelers, error: labelersError, } = useMyLabelersQuery() + const {mutateAsync: removeLabelers, isPending: isRemovingLabelers} = + useRemoveLabelersMutation() const aa = useAgeAssurance() const isBirthdateUpdateAllowed = useIsBirthdateUpdateAllowed() const aaCopy = useAgeAssuranceCopy() + const subscribedDids = preferences.moderationPrefs.labelers.map(l => l.did) + const returnedDids = new Set(labelers?.map(l => l.creator.did)) + const unavailableDids = subscribedDids.filter( + did => + !returnedDids.has(did) && + !isAppLabeler(did) && + !isNonConfigurableModerationAuthority(did), + ) + + const handleCleanup = async () => { + try { + await removeLabelers({dids: unavailableDids}) + Toast.show(_(msg`Removed unavailable services`), { + type: 'success', + }) + } catch (e: any) { + logger.error('Failed to remove unavailable labelers', { + safeMessage: e.message, + }) + } + } + useFocusEffect( useCallback(() => { setMinimalShellMode(false) @@ -209,7 +235,7 @@ export function ModerationScreenInner({ {aa.flags.adultContentDisabled && isBirthdateUpdateAllowed && ( - + Your declared age is under 18. Some settings below may be disabled. If this was a mistake, you may edit your birthdate in @@ -221,7 +247,7 @@ export function ModerationScreenInner({ . - + )} @@ -439,6 +465,31 @@ export function ModerationScreenInner({ Advanced + {unavailableDids.length > 0 && ( + + + + + + + Some moderation services in your list are no longer available. + + + + + + Remove + + {isRemovingLabelers && } + + + + )} + {isLabelersLoading ? ( diff --git a/src/state/queries/labeler.ts b/src/state/queries/labeler.ts index 465a2b57a3..9bf4372739 100644 --- a/src/state/queries/labeler.ts +++ b/src/state/queries/labeler.ts @@ -82,6 +82,22 @@ export function useLabelersDetailedInfoQuery({dids}: {dids: string[]}) { }) } +export function useRemoveLabelersMutation() { + const queryClient = useQueryClient() + const agent = useAgent() + + return useMutation({ + async mutationFn({dids}: {dids: string[]}) { + await Promise.all(dids.map(did => agent.removeLabeler(did))) + }, + async onSuccess() { + await queryClient.invalidateQueries({ + queryKey: preferencesQueryKey, + }) + }, + }) +} + export function useLabelerSubscriptionMutation() { const queryClient = useQueryClient() const agent = useAgent()