diff --git a/src/screens/ProfileModerationService/Header.tsx b/src/screens/ProfileModerationService/Header.tsx index 409136c6f2..c71c9cd30c 100644 --- a/src/screens/ProfileModerationService/Header.tsx +++ b/src/screens/ProfileModerationService/Header.tsx @@ -13,7 +13,10 @@ import {useSetDrawerOpen} from '#/state/shell' import {emitSoftReset} from '#/state/events' import {shareUrl} from '#/lib/sharing' import {sanitizeDisplayName} from '#/lib/strings/display-names' -import {NativeDropdown, DropdownItem} from '#/view/com/util/forms/NativeDropdown' +import { + NativeDropdown, + DropdownItem, +} from '#/view/com/util/forms/NativeDropdown' import {useSession} from '#/state/session' import {useModalControls} from '#/state/modals' @@ -95,7 +98,7 @@ export function Header({ a.overflow_hidden, ]}> c[1])} + colors={tokens.gradients.bonfire.values.map(c => c[1])} locations={tokens.gradients.bonfire.values.map(c => c[0])} start={{x: 0, y: 0}} end={{x: 1, y: 1}} diff --git a/src/screens/ProfileModerationService/PreferenceRow.tsx b/src/screens/ProfileModerationService/PreferenceRow.tsx new file mode 100644 index 0000000000..46f90cfda6 --- /dev/null +++ b/src/screens/ProfileModerationService/PreferenceRow.tsx @@ -0,0 +1,66 @@ +import React from 'react' +import {View} from 'react-native' +import {useLingui} from '@lingui/react' +import {msg} from '@lingui/macro' + +import { + CONFIGURABLE_LABEL_GROUPS, + ConfigurableLabelGroup, +} from '#/state/queries/preferences' + +import {useTheme, atoms as a} from '#/alf' +import {Text} from '#/components/Typography' +import * as ToggleButton from '#/components/forms/ToggleButton' + +export function PreferenceRow({ + labelGroup, +}: { + labelGroup: ConfigurableLabelGroup +}) { + const t = useTheme() + const {_} = useLingui() + const groupInfo = CONFIGURABLE_LABEL_GROUPS[labelGroup] + + const labels = { + hide: _(msg`Hide`), + warn: _(msg`Warn`), + show: _(msg`Show`), + } + + return ( + + + {groupInfo.title} + + {groupInfo.subtitle} + + + + {}}> + + {labels.hide} + + + {labels.warn} + + + {labels.show} + + + + + ) +} diff --git a/src/screens/ProfileModerationService/index.tsx b/src/screens/ProfileModerationService/index.tsx index 7af5bc154b..f46a0e62f4 100644 --- a/src/screens/ProfileModerationService/index.tsx +++ b/src/screens/ProfileModerationService/index.tsx @@ -1,32 +1,22 @@ -import React, {useMemo, useCallback} from 'react' -import {Dimensions, StyleSheet, View, ActivityIndicator} from 'react-native' +import React from 'react' +import {Dimensions, View} from 'react-native' import {NativeStackScreenProps} from '@react-navigation/native-stack' -import {useIsFocused, useNavigation} from '@react-navigation/native' -import {AppBskyModerationDefs, RichText as RichTextAPI} from '@atproto/api' -import {usePalette} from 'lib/hooks/usePalette' -import {HeartIcon, HeartIconSolid} from 'lib/icons' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {CommonNavigatorParams} from 'lib/routes/types' -import {makeRecordUri} from 'lib/strings/url-helpers' -import {s} from 'lib/styles' -import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader' -import {TextLink} from 'view/com/util/Link' -import {Button as OldButton} from 'view/com/util/forms/Button' -import {Text as RNText} from 'view/com/util/text/Text' -import {ModServicePrefs} from '#/view/com/moderation/ModServicePrefs' -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 {makeCustomFeedLink} from 'lib/routes/links' -import {pluralize} from 'lib/strings/helpers' -import {CenteredView, ScrollView} from 'view/com/util/Views' -import {NavigationProp} from 'lib/routes/types' -import {makeProfileLink} from 'lib/routes/links' -import {logger} from '#/logger' +import {AppBskyModerationDefs} from '@atproto/api' import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {useModalControls} from '#/state/modals' + +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 {useResolveDidQuery} from '#/state/queries/resolve-uri' import { @@ -40,14 +30,18 @@ import {sanitizeHandle} from '#/lib/strings/handles' import {useTheme, atoms as a} from '#/alf' import {Text} from '#/components/Typography' import {Loader} from '#/components/Loader' -import {Button, ButtonText} from '#/components/Button' -import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' -import {Heart2_Stroke2_Corner0_Rounded as Heart, Heart2_Filled_Stroke2_Corner0_Rounded as HeartFilled} from '#/components/icons/Heart2' +import {Button} from '#/components/Button' +import { + Heart2_Stroke2_Corner0_Rounded as Heart, + Heart2_Filled_Stroke2_Corner0_Rounded as HeartFilled, +} from '#/components/icons/Heart2' import {RichText} from '#/components/RichText' import {InlineLink} from '#/components/Link' +import {Divider} from '#/components/Divider' import {ErrorState} from '#/screens/ProfileModerationService/ErrorState' import {Header} from '#/screens/ProfileModerationService/Header' +import {PreferenceRow} from '#/screens/ProfileModerationService/PreferenceRow' // TODO const MIN_HEIGHT = Dimensions.get('window').height * 1.5 @@ -125,7 +119,7 @@ function ProfileModservicecreenIntermediate({modDid}: {modDid: string}) { } export function ProfileModserviceScreenInner({ - preferences, + // preferences, modInfo, }: { preferences: UsePreferencesQueryResponse @@ -144,10 +138,10 @@ export function ProfileModserviceScreenInner({ ) const isLiked = !!likeUri - const isSaved = false // TODO + // const isSaved = false // TODO // !removedFeed && // (!!savedFeed || preferences.feeds.saved.includes(feedInfo.uri)) - const isEnabled = false // TODO + // const isEnabled = false // TODO // !unpinnedFeed && // (!!pinnedFeed || preferences.feeds.pinned.includes(feedInfo.uri)) @@ -207,7 +201,13 @@ export function ProfileModserviceScreenInner({ )} - + Operated by{' '} {typeof modInfo.likeCount === 'number' && ( - - Liked by {modInfo.likeCount} {pluralize(modInfo.likeCount, 'user')} + + + Liked by {modInfo.likeCount}{' '} + {pluralize(modInfo.likeCount, 'user')} + )} - + + + + + + + + diff --git a/src/view/com/profile/ProfileHeaderModCard.tsx b/src/view/com/profile/ProfileHeaderModCard.tsx index 0ac8ef2bca..df14ec06e8 100644 --- a/src/view/com/profile/ProfileHeaderModCard.tsx +++ b/src/view/com/profile/ProfileHeaderModCard.tsx @@ -1,68 +1,73 @@ import React from 'react' -import {StyleSheet, View} from 'react-native' -import {RichText as RichTextAPI} from '@atproto/api' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {HandIcon} from '#/lib/icons' -import {Trans, msg} from '@lingui/macro' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {LoadingPlaceholder} from '../util/LoadingPlaceholder' -import {Text} from '../util/text/Text' -import {RichText} from '../util/text/RichText' -import {usePalette} from 'lib/hooks/usePalette' -import {s, colors} from 'lib/styles' -import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' +import LinearGradient from 'react-native-linear-gradient' -import {atoms as a} from '#/alf' -import {Link} from '#/components/Link' - -const richtext = new RichTextAPI({ - text: "Bluesky's official moderation service", -}) +import {atoms as a, useTheme, tokens, web} from '#/alf' +import {Link, useLinkContext} from '#/components/Link' +import {Text} from '#/components/Typography' +import {RichText} from '#/components/RichText' +import {RaisingHande4Finger_Stroke2_Corner0_Rounded as RaisingHand} from '#/components/icons/RaisingHand' export function ProfileHeaderModCard() { - const pal = usePalette('default') - const {isMobile} = useWebMediaQueries() + const {_} = useLingui() return ( - - - - {!isMobile && } - - - Moderation service - - - - {isMobile ? ( - - ) : ( - - - View - - - )} - - + + ) } -const styles = StyleSheet.create({}) +function Inner() { + const t = useTheme() + const {hovered, pressed, focused} = useLinkContext() + + return ( + + c[1])} + locations={tokens.gradients.bonfire.values.map(c => c[0])} + start={{x: 0, y: 0}} + end={{x: 1, y: 1}} + style={[a.absolute, a.inset_0]} + /> + + + + Moderation service + + + + + + + + ) +} diff --git a/src/view/screens/ProfileModservice.tsx b/src/view/screens/ProfileModservice.tsx deleted file mode 100644 index 5afc2e1788..0000000000 --- a/src/view/screens/ProfileModservice.tsx +++ /dev/null @@ -1,280 +0,0 @@ -import React, {useMemo, useCallback} from 'react' -import {Dimensions, StyleSheet, View, ActivityIndicator} from 'react-native' -import {NativeStackScreenProps} from '@react-navigation/native-stack' -import {useIsFocused, useNavigation} from '@react-navigation/native' -import {AppBskyModerationDefs, RichText as RichTextAPI} from '@atproto/api' -import {usePalette} from 'lib/hooks/usePalette' -import {HeartIcon, HeartIconSolid} from 'lib/icons' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {CommonNavigatorParams} from 'lib/routes/types' -import {makeRecordUri} from 'lib/strings/url-helpers' -import {s} from 'lib/styles' -import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader' -import {TextLink} from 'view/com/util/Link' -import {Button} from 'view/com/util/forms/Button' -import {Text} from 'view/com/util/text/Text' -import {RichText} from 'view/com/util/text/RichText' -import {ModServicePrefs} from '../com/moderation/ModServicePrefs' -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 {makeCustomFeedLink} from 'lib/routes/links' -import {pluralize} from 'lib/strings/helpers' -import {CenteredView, ScrollView} from 'view/com/util/Views' -import {NavigationProp} from 'lib/routes/types' -import {makeProfileLink} from 'lib/routes/links' -import {logger} from '#/logger' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {useModalControls} from '#/state/modals' -import {useModServiceInfoQuery} from '#/state/queries/modservice' -import {useResolveDidQuery} from '#/state/queries/resolve-uri' -import { - UsePreferencesQueryResponse, - usePreferencesQuery, -} from '#/state/queries/preferences' -import {useSession} from '#/state/session' -import {useLikeMutation, useUnlikeMutation} from '#/state/queries/like' -import {ModServiceHeader} from '../com/moderation/ModServiceHeader' -import {sanitizeHandle} from '#/lib/strings/handles' - -type Props = NativeStackScreenProps -export function ProfileModserviceScreen(props: Props) { - const {name: handleOrDid} = props.route.params - - const pal = usePalette('default') - const {_} = useLingui() - const navigation = useNavigation() - - const {error, data: resolvedDid} = useResolveDidQuery(handleOrDid) - - const onPressBack = React.useCallback(() => { - if (navigation.canGoBack()) { - navigation.goBack() - } else { - navigation.navigate('Home') - } - }, [navigation]) - - if (error) { - return ( - - - - Could not load moderation service - - - {error.toString()} - - - - - - - - ) - } - - return resolvedDid ? ( - - ) : ( - - - - - - ) -} - -function ProfileModservicecreenIntermediate({modDid}: {modDid: string}) { - const {data: preferences} = usePreferencesQuery() - const {data: info} = useModServiceInfoQuery({did: modDid}) - - if (!preferences || !info) { - return ( - - - - - - ) - } - - return ( - - ) -} - -export function ProfileModserviceScreenInner({ - preferences, - modInfo, -}: { - preferences: UsePreferencesQueryResponse - modInfo: AppBskyModerationDefs.ModServiceViewDetailed -}) { - const {_} = useLingui() - const pal = usePalette('default') - const {hasSession} = useSession() - const {track} = useAnalytics() - const {mutateAsync: likeMod, isPending: isLikePending} = useLikeMutation() - const {mutateAsync: unlikeMod, isPending: isUnlikePending} = - useUnlikeMutation() - const [likeUri, setLikeUri] = React.useState( - modInfo.viewer?.like || '', - ) - - const isLiked = !!likeUri - const isSaved = false // TODO - // !removedFeed && - // (!!savedFeed || preferences.feeds.saved.includes(feedInfo.uri)) - const isEnabled = false // TODO - // !unpinnedFeed && - // (!!pinnedFeed || preferences.feeds.pinned.includes(feedInfo.uri)) - - const descriptionRT = useMemo( - () => - modInfo.description - ? new RichTextAPI({ - text: modInfo.description, - facets: modInfo.descriptionFacets, - }) - : undefined, - [modInfo], - ) - - useSetTitle(modInfo.creator.displayName || modInfo.creator.handle) - - // event handlers - // - const onToggleLiked = React.useCallback(async () => { - try { - Haptics.default() - - if (isLiked && likeUri) { - await unlikeMod({uri: likeUri}) - track('CustomFeed:Unlike') - setLikeUri('') - } else { - const res = await likeMod({uri: modInfo.uri, cid: modInfo.cid}) - track('CustomFeed:Like') - setLikeUri(res.uri) - } - } catch (err) { - 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}) - } - }, [likeUri, isLiked, modInfo, likeMod, unlikeMod, track, _]) - - // render - // = - - return ( - - - - - {descriptionRT ? ( - - ) : ( - - No description - - )} - - - Operated by{' '} - - . Handles reports of anti-social behavior, illegal content, - unwanted sexual content, and misinformation. - - - - - - {typeof modInfo.likeCount === 'number' && ( - - )} - - - - - - - ) -} - -const styles = StyleSheet.create({ - btn: { - flexDirection: 'row', - alignItems: 'center', - gap: 6, - paddingVertical: 7, - paddingHorizontal: 14, - borderRadius: 50, - marginLeft: 6, - }, - notFoundContainer: { - margin: 10, - paddingHorizontal: 18, - paddingVertical: 14, - borderRadius: 6, - }, -})