Update enablement on ProfileMod screen

This commit is contained in:
Eric Bailey
2024-02-15 16:21:41 -06:00
parent 6d9e1f4dd9
commit c5d31cd8b0
3 changed files with 110 additions and 104 deletions
+25 -66
View File
@@ -19,11 +19,9 @@ import {
} from '#/view/com/util/forms/NativeDropdown'
import {useSession} from '#/state/session'
import {useModalControls} from '#/state/modals'
import {
useModServiceSubscriptionMutation,
useModServiceEnableMutation,
} from '#/state/queries/modservice'
import {useModServiceSubscriptionMutation} from '#/state/queries/modservice'
import {UsePreferencesQueryResponse} from '#/state/queries/preferences'
import {logger} from '#/logger'
import {useTheme, atoms as a, tokens, web, native, useBreakpoints} from '#/alf'
import {Text} from '#/components/Typography'
@@ -54,16 +52,7 @@ export function Header({
preferences.moderationOpts.mods.find(
mod => mod.did === modservice.creator.did,
)
const {mutateAsync: toggleEnabled, variables: enabledVariables} =
useModServiceEnableMutation()
const isEnabled =
enabledVariables?.enabled ??
preferences.moderationOpts.mods.find(
mod => mod.did === modservice.creator.did && mod.enabled,
) ??
variables?.subscribe
const [subscriptionError, setSubscriptionError] = React.useState<string>('')
const [enablementError, setEnablementError] = React.useState<string>('')
const onPressBack = React.useCallback(() => {
if (navigation.canGoBack()) {
@@ -85,20 +74,10 @@ export function Header({
})
} catch (e: any) {
setSubscriptionError(e.message)
logger.error(`Failed to subscribe to labeler`, {message: e.message})
}
}, [toggleSubscription, isSubscribed, modservice.creator.did])
const onPressEnable = React.useCallback(async () => {
try {
await toggleEnabled({
did: modservice.creator.did,
enabled: !isEnabled,
})
} catch (e: any) {
setEnablementError(e.message)
}
}, [toggleEnabled, isEnabled, modservice.creator.did])
return (
<View style={[a.pb_xl, web(a.pt_md), gtMobile && web(a.pt_2xl)]}>
{!gtMobile && (
@@ -179,23 +158,6 @@ export function Header({
{gtMobile && (
<View style={[a.flex_row, a.align_center, a.gap_md]}>
{isSubscribed && (
<Button
size="small"
variant="solid"
color="secondary"
label={
isEnabled
? _(msg`Disable this moderation service`)
: _(msg`Enable this moderation service`)
}
onPress={onPressEnable}>
<ButtonText>
{isEnabled ? <Trans>Disable</Trans> : <Trans>Enable</Trans>}
</ButtonText>
</Button>
)}
<Button
size="small"
variant="solid"
@@ -220,32 +182,29 @@ export function Header({
)}
</View>
{subscriptionError ||
(enablementError && (
<View style={[a.pt_lg]}>
<View
style={[
a.px_lg,
a.py_md,
a.rounded_sm,
a.border,
a.gap_xs,
{
backgroundColor: t.palette.negative_50,
borderColor: t.palette.negative_100,
},
]}>
<Text style={[a.font_bold, {color: t.palette.negative_950}]}>
<Trans>
An error occurred while editing your subscription.
</Trans>
</Text>
<Text style={[{color: t.palette.negative_900}]}>
{subscriptionError || enablementError}
</Text>
</View>
{subscriptionError && (
<View style={[a.pt_lg]}>
<View
style={[
a.px_lg,
a.py_md,
a.rounded_sm,
a.border,
a.gap_xs,
{
backgroundColor: t.palette.negative_50,
borderColor: t.palette.negative_100,
},
]}>
<Text style={[a.font_bold, {color: t.palette.negative_950}]}>
<Trans>An error occurred while editing your subscription.</Trans>
</Text>
<Text style={[{color: t.palette.negative_900}]}>
{subscriptionError || enablementError}
</Text>
</View>
))}
</View>
)}
</View>
)
}
@@ -2,13 +2,13 @@ import React from 'react'
import {View} from 'react-native'
import {useLingui} from '@lingui/react'
import {msg} from '@lingui/macro'
// import {msg} from '@lingui/macro'
import {LABEL_GROUPS} from '@atproto/api'
// TODO
import {ModPrefItem} from '@atproto/api/dist/client/types/app/bsky/actor/defs'
import {useLabelGroupStrings} from '#/lib/moderation/useLabelGroupStrings'
import {useModServiceLabelGroupEnableMutation} from '#/state/queries/modservice'
import {logger} from '#/logger'
import {useTheme, atoms as a} from '#/alf'
import {Text} from '#/components/Typography'
@@ -16,9 +16,11 @@ import * as Toggle from '#/components/forms/Toggle'
export function PreferenceRow({
labelGroup,
disabled,
modservicePreferences,
}: {
labelGroup: keyof typeof LABEL_GROUPS
disabled?: boolean
modservicePreferences?: ModPrefItem
}) {
const t = useTheme()
@@ -32,15 +34,19 @@ export function PreferenceRow({
const onToggleEnabled = React.useCallback(async () => {
try {
if (!modservicePreferences)
throw new Error(`modservicePreferences not found`)
await mutateAsync({
// @ts-ignore TODO
did: modservicePreferences?.did,
did: modservicePreferences.did,
group: labelGroup,
enabled: !enabled,
})
} catch (e: any) {
// TODO
console.error(e)
logger.error(`Failed to toggle label group enabled`, {
message: e.message,
labelGroup,
})
}
}, [mutateAsync, enabled, modservicePreferences, labelGroup])
@@ -62,8 +68,9 @@ export function PreferenceRow({
<View style={[a.justify_center, {minHeight: 35}]}>
{modservicePreferences && (
<Toggle.Item
disabled={disabled}
name="enable"
value={enabled}
value={disabled ? false : enabled}
onChange={onToggleEnabled}
label={_(msg`Enable`)}>
<Toggle.Label>{enabled ? 'Enabled' : 'Disabled'}</Toggle.Label>
+72 -32
View File
@@ -6,19 +6,18 @@ import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useSafeAreaFrame} from 'react-native-safe-area-context'
import {usePalette} from '#/lib/hooks/usePalette'
import {CommonNavigatorParams} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {TextLink} from '#/view/com/util/Link'
import * as Toast from '#/view/com/util/Toast'
import {useSetTitle} from '#/lib/hooks/useSetTitle'
import {Haptics} from '#/lib/haptics'
import {useAnalytics} from '#/lib/analytics/analytics'
import {pluralize} from '#/lib/strings/helpers'
import {CenteredView, ScrollView} from '#/view/com/util/Views'
import {makeProfileLink} from '#/lib/routes/links'
import {logger} from '#/logger'
import {useModServiceInfoQuery} from '#/state/queries/modservice'
import {
useModServiceInfoQuery,
useModServiceEnableMutation,
} from '#/state/queries/modservice'
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
import {
UsePreferencesQueryResponse,
@@ -26,7 +25,6 @@ import {
} from '#/state/queries/preferences'
import {useSession} from '#/state/session'
import {useLikeMutation, useUnlikeMutation} from '#/state/queries/like'
import {sanitizeHandle} from '#/lib/strings/handles'
import {getLabelGroupsFromLabels} from '#/lib/moderation'
@@ -41,6 +39,7 @@ import {
import {RichText} from '#/components/RichText'
import {InlineLink} from '#/components/Link'
import {Divider} from '#/components/Divider'
import * as Toggle from '#/components/forms/Toggle'
import {ErrorState} from '#/screens/ProfileModerationService/ErrorState'
import {Header} from '#/screens/ProfileModerationService/Header'
@@ -116,15 +115,20 @@ export function ProfileModserviceScreenInner({
const t = useTheme()
const {_} = useLingui()
const {height: minHeight} = useSafeAreaFrame()
const pal = usePalette('default')
const {hasSession} = useSession()
const {track} = useAnalytics()
const {mutateAsync: likeMod, isPending: isLikePending} = useLikeMutation()
const {mutateAsync: unlikeMod, isPending: isUnlikePending} =
useUnlikeMutation()
const {mutateAsync: toggleEnabled, variables: enabledVariables} =
useModServiceEnableMutation()
const [likeUri, setLikeUri] = React.useState<string>(
modservice.viewer?.like || '',
)
// TODO error state
const [_enablementError, setEnablementError] = React.useState<string>('')
const isLiked = !!likeUri
const groups = React.useMemo(() => {
return getLabelGroupsFromLabels(modservice.policies.labelValues).filter(
@@ -136,6 +140,12 @@ export function ProfileModserviceScreenInner({
p => p.did === modservice.creator.did,
)
}, [modservice.creator.did, preferences.moderationOpts.mods])
const isEnabled = Boolean(
enabledVariables?.enabled ??
preferences.moderationOpts.mods.find(
mod => mod.did === modservice.creator.did && mod.enabled,
),
)
useSetTitle(modservice.creator.displayName || modservice.creator.handle)
@@ -152,16 +162,28 @@ export function ProfileModserviceScreenInner({
track('CustomFeed:Like')
setLikeUri(res.uri)
}
} catch (err) {
} catch (e: any) {
Toast.show(
_(
msg`There was an an issue contacting the server, please check your internet connection and try again.`,
),
)
logger.error('Failed up toggle like', {error: err})
logger.error(`Failed to toggle labeler like`, {message: e.message})
}
}, [likeUri, isLiked, modservice, likeMod, unlikeMod, track, _])
const onToggleLabelerEnabled = React.useCallback(async () => {
try {
await toggleEnabled({
did: modservice.creator.did,
enabled: !isEnabled,
})
} catch (e: any) {
setEnablementError(e.message)
logger.error(`Failed to toggle labeler enabled`, {message: e.message})
}
}, [toggleEnabled, isEnabled, modservice.creator.did])
return (
<ScrollView
scrollEventThrottle={1}
@@ -194,25 +216,6 @@ export function ProfileModserviceScreenInner({
</Text>
)}
<Text
style={[
a.text_md,
a.leading_normal,
a.italic,
t.atoms.text_contrast_medium,
]}>
<Trans>
Operated by{' '}
<TextLink
href={makeProfileLink(modservice.creator)}
text={sanitizeHandle(modservice.creator.handle, '@')}
style={pal.link}
/>
. Handles reports of anti-social behavior, illegal content, unwanted
sexual content, and misinformation.
</Trans>
</Text>
<View style={[a.flex_row, a.gap_md, a.align_center]}>
<Button
testID="toggleLikeBtn"
@@ -231,7 +234,9 @@ export function ProfileModserviceScreenInner({
</Button>
{typeof modservice.likeCount === 'number' && (
<InlineLink to={'#todo'} style={[pal.textLight, s.semiBold]}>
<InlineLink
to={'#todo'}
style={[t.atoms.text_contrast_medium, a.font_bold]}>
<Trans>
Liked by {modservice.likeCount}{' '}
{pluralize(modservice.likeCount, 'user')}
@@ -248,18 +253,53 @@ export function ProfileModserviceScreenInner({
Configure moderation service
</Text>
<Text style={[t.atoms.text_contrast_high, a.leading_snug]}>
This moderation service supports the following types of content.
Configure which types of content you'd like to respect from this
service.
This labeler moderates the following types of content. You can
optionally enable or disable the labeler's recommendations for each
type of content below.
</Text>
</View>
<View style={[a.w_full, a.mt_xl]}>
<Toggle.Item
name="enable"
value={isEnabled}
onChange={onToggleLabelerEnabled}
label={
isEnabled
? _(msg`Disable this moderation service`)
: _(msg`Enable this moderation service`)
}>
<View
style={[
a.w_full,
a.flex_row,
a.justify_between,
a.gap_lg,
a.p_md,
a.rounded_sm,
t.atoms.bg_contrast_25,
]}>
<View style={[a.flex_1]}>
<Text style={[a.font_bold, a.pb_xs]}>
This service is {isEnabled ? 'enabled' : 'disabled'}
</Text>
<Text style={[t.atoms.text_contrast_medium, a.leading_snug]}>
Optionally disable this service without affecting your
subscription.
</Text>
</View>
<Toggle.Switch />
</View>
</Toggle.Item>
</View>
<View style={[a.gap_md, a.mt_xl]}>
{groups.map((def, i) => {
return (
<React.Fragment key={def.id}>
{i !== 0 && <Divider />}
<PreferenceRow
disabled={isEnabled ? undefined : true}
labelGroup={def.id}
modservicePreferences={modservicePreferences}
/>