Wire up more of the modservice data to profiles
This commit is contained in:
@@ -2,6 +2,7 @@ import React, {memo, useMemo} from 'react'
|
|||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {
|
import {
|
||||||
AppBskyActorDefs,
|
AppBskyActorDefs,
|
||||||
|
AppBskyModerationDefs,
|
||||||
ModerationOpts,
|
ModerationOpts,
|
||||||
moderateProfile,
|
moderateProfile,
|
||||||
RichText as RichTextAPI,
|
RichText as RichTextAPI,
|
||||||
@@ -36,6 +37,7 @@ import {
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||||
|
modservice: AppBskyModerationDefs.ModServiceViewDetailed
|
||||||
descriptionRT: RichTextAPI | null
|
descriptionRT: RichTextAPI | null
|
||||||
moderationOpts: ModerationOpts
|
moderationOpts: ModerationOpts
|
||||||
hideBackButton?: boolean
|
hideBackButton?: boolean
|
||||||
@@ -44,6 +46,7 @@ interface Props {
|
|||||||
|
|
||||||
let ProfileHeaderModerator = ({
|
let ProfileHeaderModerator = ({
|
||||||
profile: profileUnshadowed,
|
profile: profileUnshadowed,
|
||||||
|
modservice,
|
||||||
descriptionRT,
|
descriptionRT,
|
||||||
moderationOpts,
|
moderationOpts,
|
||||||
hideBackButton = false,
|
hideBackButton = false,
|
||||||
@@ -66,16 +69,18 @@ let ProfileHeaderModerator = ({
|
|||||||
const isSubscribed =
|
const isSubscribed =
|
||||||
variables?.subscribe ??
|
variables?.subscribe ??
|
||||||
preferences?.moderationOpts.mods.find(mod => mod.did === profile.did)
|
preferences?.moderationOpts.mods.find(mod => mod.did === profile.did)
|
||||||
const modservice = {likeCount: 0} // TODO
|
|
||||||
const {mutateAsync: likeMod, isPending: isLikePending} = useLikeMutation()
|
const {mutateAsync: likeMod, isPending: isLikePending} = useLikeMutation()
|
||||||
const {mutateAsync: unlikeMod, isPending: isUnlikePending} =
|
const {mutateAsync: unlikeMod, isPending: isUnlikePending} =
|
||||||
useUnlikeMutation()
|
useUnlikeMutation()
|
||||||
const [likeUri, setLikeUri] = React.useState<string>(
|
const [likeUri, setLikeUri] = React.useState<string>(
|
||||||
/* TODO modservice.viewer?.like ||*/ '',
|
modservice.viewer?.like || '',
|
||||||
)
|
)
|
||||||
const isLiked = !!likeUri
|
const isLiked = !!likeUri
|
||||||
|
|
||||||
const onToggleLiked = React.useCallback(async () => {
|
const onToggleLiked = React.useCallback(async () => {
|
||||||
|
if (!modservice) {
|
||||||
|
return
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Haptics.default()
|
Haptics.default()
|
||||||
|
|
||||||
@@ -84,10 +89,9 @@ let ProfileHeaderModerator = ({
|
|||||||
track('CustomFeed:Unlike')
|
track('CustomFeed:Unlike')
|
||||||
setLikeUri('')
|
setLikeUri('')
|
||||||
} else {
|
} 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')
|
track('CustomFeed:Like')
|
||||||
// setLikeUri(res.uri)
|
setLikeUri(res.uri)
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
Toast.show(
|
Toast.show(
|
||||||
@@ -97,7 +101,7 @@ let ProfileHeaderModerator = ({
|
|||||||
)
|
)
|
||||||
logger.error(`Failed to toggle labeler like`, {message: e.message})
|
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(() => {
|
const onPressEditProfile = React.useCallback(() => {
|
||||||
track('ProfileHeader:EditProfileButtonClicked')
|
track('ProfileHeader:EditProfileButtonClicked')
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import {sanitizeDisplayName} from 'lib/strings/display-names'
|
|||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {InlineLink} from '#/components/Link'
|
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 * as Toast from '#/view/com/util/Toast'
|
||||||
import {ProfileHeaderShell} from './Shell'
|
import {ProfileHeaderShell} from './Shell'
|
||||||
import {ProfileHeaderDropdownBtn} from './DropdownBtn'
|
import {ProfileHeaderDropdownBtn} from './DropdownBtn'
|
||||||
@@ -36,6 +36,8 @@ import {ProfileHeaderDisplayName} from './DisplayName'
|
|||||||
import {ProfileHeaderHandle} from './Handle'
|
import {ProfileHeaderHandle} from './Handle'
|
||||||
import {ProfileHeaderSuggestedFollows} from '#/view/com/profile/ProfileHeaderSuggestedFollows'
|
import {ProfileHeaderSuggestedFollows} from '#/view/com/profile/ProfileHeaderSuggestedFollows'
|
||||||
import {RichText} from 'view/com/util/text/RichText'
|
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 {
|
interface Props {
|
||||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||||
@@ -224,7 +226,11 @@ let ProfileHeaderStandard = ({
|
|||||||
onPress={
|
onPress={
|
||||||
profile.viewer?.following ? onPressUnfollow : onPressFollow
|
profile.viewer?.following ? onPressUnfollow : onPressFollow
|
||||||
}
|
}
|
||||||
style={a.rounded_full}>
|
style={[a.rounded_full, a.gap_xs]}>
|
||||||
|
<ButtonIcon
|
||||||
|
position="left"
|
||||||
|
icon={profile.viewer?.following ? Check : Plus}
|
||||||
|
/>
|
||||||
<ButtonText>
|
<ButtonText>
|
||||||
{profile.viewer?.following ? (
|
{profile.viewer?.following ? (
|
||||||
<Trans>Following</Trans>
|
<Trans>Following</Trans>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, {memo} from 'react'
|
|||||||
import {StyleSheet, View} from 'react-native'
|
import {StyleSheet, View} from 'react-native'
|
||||||
import {
|
import {
|
||||||
AppBskyActorDefs,
|
AppBskyActorDefs,
|
||||||
|
AppBskyModerationDefs,
|
||||||
ModerationOpts,
|
ModerationOpts,
|
||||||
RichText as RichTextAPI,
|
RichText as RichTextAPI,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
@@ -33,6 +34,7 @@ export {ProfileHeaderLoading}
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||||
|
modservice: AppBskyModerationDefs.ModServiceViewDetailed | undefined
|
||||||
descriptionRT: RichTextAPI | null
|
descriptionRT: RichTextAPI | null
|
||||||
moderationOpts: ModerationOpts
|
moderationOpts: ModerationOpts
|
||||||
hideBackButton?: boolean
|
hideBackButton?: boolean
|
||||||
@@ -41,7 +43,10 @@ interface Props {
|
|||||||
|
|
||||||
let ProfileHeader = (props: Props): React.ReactNode => {
|
let ProfileHeader = (props: Props): React.ReactNode => {
|
||||||
if (props.profile.associated?.modservice) {
|
if (props.profile.associated?.modservice) {
|
||||||
return <ProfileHeaderModerator {...props} />
|
if (!props.modservice) {
|
||||||
|
return <ProfileHeaderLoading />
|
||||||
|
}
|
||||||
|
return <ProfileHeaderModerator {...props} modservice={props.modservice} />
|
||||||
}
|
}
|
||||||
return <ProfileHeaderStandard {...props} />
|
return <ProfileHeaderStandard {...props} />
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-38
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {AppBskyModerationDefs, AppBskyActorDefs} from '@atproto/api'
|
import {AppBskyModerationDefs, ModerationOpts} from '@atproto/api'
|
||||||
import {Trans, msg} from '@lingui/macro'
|
import {Trans, msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useSafeAreaFrame} from 'react-native-safe-area-context'
|
import {useSafeAreaFrame} from 'react-native-safe-area-context'
|
||||||
@@ -11,14 +11,7 @@ import {Haptics} from '#/lib/haptics'
|
|||||||
import {useAnalytics} from '#/lib/analytics/analytics'
|
import {useAnalytics} from '#/lib/analytics/analytics'
|
||||||
import {CenteredView, ScrollView} from '#/view/com/util/Views'
|
import {CenteredView, ScrollView} from '#/view/com/util/Views'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {
|
import {useModServiceEnableMutation} from '#/state/queries/modservice'
|
||||||
useModServiceInfoQuery,
|
|
||||||
useModServiceEnableMutation,
|
|
||||||
} from '#/state/queries/modservice'
|
|
||||||
import {
|
|
||||||
UsePreferencesQueryResponse,
|
|
||||||
usePreferencesQuery,
|
|
||||||
} from '#/state/queries/preferences'
|
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useLikeMutation, useUnlikeMutation} from '#/state/queries/like'
|
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 {ErrorState} from '#/screens/ProfileModerationService/ErrorState'
|
||||||
import {PreferenceRow} from '#/screens/ProfileModerationService/PreferenceRow'
|
import {PreferenceRow} from '#/screens/ProfileModerationService/PreferenceRow'
|
||||||
|
|
||||||
export function ProfileFiltersSection({
|
export function ProfileContentFiltersSection({
|
||||||
profile,
|
modServiceQuery,
|
||||||
|
moderationOpts,
|
||||||
}: {
|
}: {
|
||||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
modServiceQuery: {
|
||||||
|
data: AppBskyModerationDefs.ModServiceViewDetailed | undefined
|
||||||
|
isLoading: boolean
|
||||||
|
error: Error | null
|
||||||
|
}
|
||||||
|
moderationOpts: ModerationOpts
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {height: minHeight} = useSafeAreaFrame()
|
const {height: minHeight} = useSafeAreaFrame()
|
||||||
const {
|
const {isLoading, error, data: modservice} = modServiceQuery
|
||||||
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
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CenteredView>
|
<CenteredView>
|
||||||
<View
|
<View
|
||||||
@@ -71,7 +57,7 @@ export function ProfileFiltersSection({
|
|||||||
<View style={[a.w_full, a.align_center]}>
|
<View style={[a.w_full, a.align_center]}>
|
||||||
<Loader size="xl" />
|
<Loader size="xl" />
|
||||||
</View>
|
</View>
|
||||||
) : error || !(preferences && modservice) ? (
|
) : error || !modservice ? (
|
||||||
<ErrorState
|
<ErrorState
|
||||||
error={
|
error={
|
||||||
error?.toString() ||
|
error?.toString() ||
|
||||||
@@ -79,8 +65,8 @@ export function ProfileFiltersSection({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ProfileFiltersSectionInner
|
<ProfileContentFiltersSectionInner
|
||||||
preferences={preferences}
|
moderationOpts={moderationOpts}
|
||||||
modservice={modservice}
|
modservice={modservice}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -89,11 +75,11 @@ export function ProfileFiltersSection({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ProfileFiltersSectionInner({
|
export function ProfileContentFiltersSectionInner({
|
||||||
preferences,
|
moderationOpts,
|
||||||
modservice,
|
modservice,
|
||||||
}: {
|
}: {
|
||||||
preferences: UsePreferencesQueryResponse
|
moderationOpts: ModerationOpts
|
||||||
modservice: AppBskyModerationDefs.ModServiceViewDetailed
|
modservice: AppBskyModerationDefs.ModServiceViewDetailed
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
@@ -119,16 +105,14 @@ export function ProfileFiltersSectionInner({
|
|||||||
)
|
)
|
||||||
}, [modservice.policies.labelValues])
|
}, [modservice.policies.labelValues])
|
||||||
const modservicePreferences = React.useMemo(() => {
|
const modservicePreferences = React.useMemo(() => {
|
||||||
return preferences.moderationOpts.mods.find(
|
return moderationOpts.mods.find(p => p.did === modservice.creator.did)
|
||||||
p => p.did === modservice.creator.did,
|
}, [modservice.creator.did, moderationOpts.mods])
|
||||||
)
|
const isSubscribed = moderationOpts.mods.find(
|
||||||
}, [modservice.creator.did, preferences.moderationOpts.mods])
|
|
||||||
const isSubscribed = preferences.moderationOpts.mods.find(
|
|
||||||
mod => mod.did === modservice.creator.did,
|
mod => mod.did === modservice.creator.did,
|
||||||
)
|
)
|
||||||
const isEnabled = Boolean(
|
const isEnabled = Boolean(
|
||||||
enabledVariables?.enabled ??
|
enabledVariables?.enabled ??
|
||||||
preferences.moderationOpts.mods.find(
|
moderationOpts.mods.find(
|
||||||
mod => mod.did === modservice.creator.did && mod.enabled,
|
mod => mod.did === modservice.creator.did && mod.enabled,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -15,9 +15,15 @@ export const modServicesDetailedInfoQueryKey = (dids: string[]) => [
|
|||||||
dids,
|
dids,
|
||||||
]
|
]
|
||||||
|
|
||||||
export function useModServiceInfoQuery({did}: {did?: string}) {
|
export function useModServiceInfoQuery({
|
||||||
|
did,
|
||||||
|
enabled,
|
||||||
|
}: {
|
||||||
|
did?: string
|
||||||
|
enabled?: boolean
|
||||||
|
}) {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
enabled: !!did,
|
enabled: !!did && enabled !== false,
|
||||||
queryKey: modServiceInfoQueryKey(did as string),
|
queryKey: modServiceInfoQueryKey(did as string),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await getAgent().app.bsky.moderation.getService({
|
const res = await getAgent().app.bsky.moderation.getService({
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import {useProfileShadow} from '#/state/cache/profile-shadow'
|
|||||||
import {useSession, getAgent} from '#/state/session'
|
import {useSession, getAgent} from '#/state/session'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
import {useModerationOpts} from '#/state/queries/preferences'
|
||||||
import {useProfileExtraInfoQuery} from '#/state/queries/profile-extra-info'
|
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 {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
|
||||||
import {useSetDrawerSwipeDisabled, useSetMinimalShellMode} from '#/state/shell'
|
import {useSetDrawerSwipeDisabled, useSetMinimalShellMode} from '#/state/shell'
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
@@ -52,7 +53,7 @@ import {isInvalidHandle} from '#/lib/strings/handles'
|
|||||||
import {useTheme, atoms as a} from '#/alf'
|
import {useTheme, atoms as a} from '#/alf'
|
||||||
import * as ModerationServiceCard from '#/components/ModerationServiceCard'
|
import * as ModerationServiceCard from '#/components/ModerationServiceCard'
|
||||||
import {RaisingHande4Finger_Stroke2_Corner0_Rounded as RaisingHand} from '#/components/icons/RaisingHand'
|
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'
|
import {ProfileHeader as ProfileHeaderV2} from '#/screens/Profile/Header'
|
||||||
|
|
||||||
interface SectionRef {
|
interface SectionRef {
|
||||||
@@ -449,6 +450,10 @@ function ProfileScreenLoadedV2({
|
|||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
const {openComposer} = useComposerControls()
|
const {openComposer} = useComposerControls()
|
||||||
const {screen, track} = useAnalytics()
|
const {screen, track} = useAnalytics()
|
||||||
|
const modServiceQuery = useModServiceInfoQuery({
|
||||||
|
did: profile.did,
|
||||||
|
enabled: !!profile.associated?.modservice,
|
||||||
|
})
|
||||||
const [currentPage, setCurrentPage] = React.useState(0)
|
const [currentPage, setCurrentPage] = React.useState(0)
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
|
const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
|
||||||
@@ -616,6 +621,7 @@ function ProfileScreenLoadedV2({
|
|||||||
return (
|
return (
|
||||||
<ProfileHeaderV2
|
<ProfileHeaderV2
|
||||||
profile={profile}
|
profile={profile}
|
||||||
|
modservice={modServiceQuery.data}
|
||||||
descriptionRT={hasDescription ? descriptionRT : null}
|
descriptionRT={hasDescription ? descriptionRT : null}
|
||||||
moderationOpts={moderationOpts}
|
moderationOpts={moderationOpts}
|
||||||
hideBackButton={hideBackButton}
|
hideBackButton={hideBackButton}
|
||||||
@@ -624,6 +630,7 @@ function ProfileScreenLoadedV2({
|
|||||||
)
|
)
|
||||||
}, [
|
}, [
|
||||||
profile,
|
profile,
|
||||||
|
modServiceQuery,
|
||||||
descriptionRT,
|
descriptionRT,
|
||||||
hasDescription,
|
hasDescription,
|
||||||
moderationOpts,
|
moderationOpts,
|
||||||
@@ -646,9 +653,10 @@ function ProfileScreenLoadedV2({
|
|||||||
renderHeader={renderHeader}>
|
renderHeader={renderHeader}>
|
||||||
{showFiltersTab
|
{showFiltersTab
|
||||||
? ({headerHeight, isFocused, scrollElRef}) => (
|
? ({headerHeight, isFocused, scrollElRef}) => (
|
||||||
<ProfileFiltersSection
|
<ProfileContentFiltersSection
|
||||||
// ref={moderationSectionRef}
|
// ref={moderationSectionRef}
|
||||||
profile={profile}
|
modServiceQuery={modServiceQuery}
|
||||||
|
moderationOpts={moderationOpts}
|
||||||
scrollElRef={scrollElRef as ListRef}
|
scrollElRef={scrollElRef as ListRef}
|
||||||
headerOffset={headerHeight}
|
headerOffset={headerHeight}
|
||||||
enabled={isFocused}
|
enabled={isFocused}
|
||||||
@@ -860,55 +868,6 @@ function ModerationSection({did}: {did: string}) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function FiltersSection({did}: {did: string}) {
|
|
||||||
const t = useTheme()
|
|
||||||
return (
|
|
||||||
<ScrollView>
|
|
||||||
<ModerationServiceCard.Loader
|
|
||||||
did={did}
|
|
||||||
component={({modservice}) => (
|
|
||||||
<ModerationServiceCard.Link modservice={modservice}>
|
|
||||||
{ctx => (
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
a.flex_1,
|
|
||||||
a.flex_row,
|
|
||||||
a.align_center,
|
|
||||||
a.gap_md,
|
|
||||||
a.p_md,
|
|
||||||
a.border_t,
|
|
||||||
t.atoms.border_contrast_low,
|
|
||||||
...(ctx.focused || ctx.hovered
|
|
||||||
? [t.atoms.bg_contrast_25]
|
|
||||||
: []),
|
|
||||||
]}>
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
{backgroundColor: t.palette.negative_25},
|
|
||||||
a.p_lg,
|
|
||||||
a.rounded_sm,
|
|
||||||
]}>
|
|
||||||
<RaisingHand
|
|
||||||
width={36}
|
|
||||||
style={[a.z_10]}
|
|
||||||
fill={t.palette.negative_500}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<ModerationServiceCard.Card.Content
|
|
||||||
title="Moderation service"
|
|
||||||
description={modservice.description}
|
|
||||||
handle={modservice.creator.handle}
|
|
||||||
likeCount={modservice.likeCount}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</ModerationServiceCard.Link>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</ScrollView>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function useRichText(text: string): [RichTextAPI, boolean] {
|
function useRichText(text: string): [RichTextAPI, boolean] {
|
||||||
const [prevText, setPrevText] = React.useState(text)
|
const [prevText, setPrevText] = React.useState(text)
|
||||||
const [rawRT, setRawRT] = React.useState(() => new RichTextAPI({text}))
|
const [rawRT, setRawRT] = React.useState(() => new RichTextAPI({text}))
|
||||||
|
|||||||
Reference in New Issue
Block a user