Optimistic hidden replies (#4977)
parent
5ec8761b29
commit
425dd5f27f
|
@ -21,7 +21,6 @@ export interface PostShadow {
|
||||||
repostUri: string | undefined
|
repostUri: string | undefined
|
||||||
isDeleted: boolean
|
isDeleted: boolean
|
||||||
embed: AppBskyEmbedRecord.View | AppBskyEmbedRecordWithMedia.View | undefined
|
embed: AppBskyEmbedRecord.View | AppBskyEmbedRecordWithMedia.View | undefined
|
||||||
threadgateView: AppBskyFeedDefs.ThreadgateView | undefined
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const POST_TOMBSTONE = Symbol('PostTombstone')
|
export const POST_TOMBSTONE = Symbol('PostTombstone')
|
||||||
|
@ -105,16 +104,6 @@ function mergeShadow(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let threadgateView: typeof post.threadgate
|
|
||||||
if ('threadgateView' in shadow && !post.threadgate) {
|
|
||||||
if (
|
|
||||||
AppBskyFeedDefs.isThreadgateView(shadow.threadgateView) ||
|
|
||||||
shadow.threadgateView === undefined
|
|
||||||
) {
|
|
||||||
threadgateView = shadow.threadgateView
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return castAsShadow({
|
return castAsShadow({
|
||||||
...post,
|
...post,
|
||||||
embed: embed || post.embed,
|
embed: embed || post.embed,
|
||||||
|
@ -125,8 +114,6 @@ function mergeShadow(
|
||||||
like: 'likeUri' in shadow ? shadow.likeUri : post.viewer?.like,
|
like: 'likeUri' in shadow ? shadow.likeUri : post.viewer?.like,
|
||||||
repost: 'repostUri' in shadow ? shadow.repostUri : post.viewer?.repost,
|
repost: 'repostUri' in shadow ? shadow.repostUri : post.viewer?.repost,
|
||||||
},
|
},
|
||||||
// always prefer real post data
|
|
||||||
threadgate: post.threadgate || threadgateView,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,10 @@ export type ThreadModerationCache = WeakMap<ThreadNode, ModerationDecision>
|
||||||
export function usePostThreadQuery(uri: string | undefined) {
|
export function usePostThreadQuery(uri: string | undefined) {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
return useQuery<ThreadNode, Error>({
|
return useQuery<
|
||||||
|
{thread: ThreadNode; threadgate?: AppBskyFeedDefs.ThreadgateView},
|
||||||
|
Error
|
||||||
|
>({
|
||||||
gcTime: 0,
|
gcTime: 0,
|
||||||
queryKey: RQKEY(uri || ''),
|
queryKey: RQKEY(uri || ''),
|
||||||
async queryFn() {
|
async queryFn() {
|
||||||
|
@ -99,16 +102,21 @@ export function usePostThreadQuery(uri: string | undefined) {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
const thread = responseToThreadNodes(res.data.thread)
|
const thread = responseToThreadNodes(res.data.thread)
|
||||||
annotateSelfThread(thread)
|
annotateSelfThread(thread)
|
||||||
return thread
|
return {
|
||||||
|
thread,
|
||||||
|
threadgate: res.data.threadgate as
|
||||||
|
| AppBskyFeedDefs.ThreadgateView
|
||||||
|
| undefined,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {type: 'unknown', uri: uri!}
|
return {thread: {type: 'unknown', uri: uri!}}
|
||||||
},
|
},
|
||||||
enabled: !!uri,
|
enabled: !!uri,
|
||||||
placeholderData: () => {
|
placeholderData: () => {
|
||||||
if (!uri) return
|
if (!uri) return
|
||||||
const post = findPostInQueryData(queryClient, uri)
|
const post = findPostInQueryData(queryClient, uri)
|
||||||
if (post) {
|
if (post) {
|
||||||
return post
|
return {thread: post}
|
||||||
}
|
}
|
||||||
return undefined
|
return undefined
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,12 +9,10 @@ import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {networkRetry, retry} from '#/lib/async/retry'
|
import {networkRetry, retry} from '#/lib/async/retry'
|
||||||
import {until} from '#/lib/async/until'
|
import {until} from '#/lib/async/until'
|
||||||
import {updatePostShadow} from '#/state/cache/post-shadow'
|
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {RQKEY_ROOT as postThreadQueryKeyRoot} from '#/state/queries/post-thread'
|
import {RQKEY_ROOT as postThreadQueryKeyRoot} from '#/state/queries/post-thread'
|
||||||
import {ThreadgateAllowUISetting} from '#/state/queries/threadgate/types'
|
import {ThreadgateAllowUISetting} from '#/state/queries/threadgate/types'
|
||||||
import {
|
import {
|
||||||
createTempThreadgateView,
|
|
||||||
createThreadgateRecord,
|
createThreadgateRecord,
|
||||||
mergeThreadgateRecords,
|
mergeThreadgateRecords,
|
||||||
threadgateAllowUISettingToAllowRecordValue,
|
threadgateAllowUISettingToAllowRecordValue,
|
||||||
|
@ -33,18 +31,16 @@ export const createThreadgateRecordQueryKey = (uri: string) => [
|
||||||
]
|
]
|
||||||
|
|
||||||
export function useThreadgateRecordQuery({
|
export function useThreadgateRecordQuery({
|
||||||
enabled,
|
|
||||||
postUri,
|
postUri,
|
||||||
initialData,
|
initialData,
|
||||||
}: {
|
}: {
|
||||||
enabled?: boolean
|
|
||||||
postUri?: string
|
postUri?: string
|
||||||
initialData?: AppBskyFeedThreadgate.Record
|
initialData?: AppBskyFeedThreadgate.Record
|
||||||
} = {}) {
|
} = {}) {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
enabled: enabled ?? !!postUri,
|
enabled: !!postUri,
|
||||||
queryKey: createThreadgateRecordQueryKey(postUri || ''),
|
queryKey: createThreadgateRecordQueryKey(postUri || ''),
|
||||||
placeholderData: initialData,
|
placeholderData: initialData,
|
||||||
staleTime: STALE.MINUTES.ONE,
|
staleTime: STALE.MINUTES.ONE,
|
||||||
|
@ -344,26 +340,17 @@ export function useToggleReplyVisibilityMutation() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onSuccess(_, {postUri, replyUri}) {
|
onSuccess() {
|
||||||
updatePostShadow(queryClient, postUri, {
|
|
||||||
threadgateView: createTempThreadgateView({
|
|
||||||
postUri,
|
|
||||||
hiddenReplies: [replyUri],
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: [threadgateRecordQueryKeyRoot],
|
queryKey: [threadgateRecordQueryKeyRoot],
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onError(_, {postUri, replyUri, action}) {
|
onError(_, {replyUri, action}) {
|
||||||
if (action === 'hide') {
|
if (action === 'hide') {
|
||||||
hiddenReplies.removeHiddenReplyUri(replyUri)
|
hiddenReplies.removeHiddenReplyUri(replyUri)
|
||||||
} else if (action === 'show') {
|
} else if (action === 'show') {
|
||||||
hiddenReplies.addHiddenReplyUri(replyUri)
|
hiddenReplies.addHiddenReplyUri(replyUri)
|
||||||
}
|
}
|
||||||
updatePostShadow(queryClient, postUri, {
|
|
||||||
threadgateView: undefined,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,23 +139,3 @@ export function createThreadgateRecord(
|
||||||
hiddenReplies: threadgate.hiddenReplies || [],
|
hiddenReplies: threadgate.hiddenReplies || [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTempThreadgateView({
|
|
||||||
postUri,
|
|
||||||
hiddenReplies,
|
|
||||||
}: Pick<AppBskyFeedThreadgate.Record, 'hiddenReplies'> & {
|
|
||||||
postUri: string
|
|
||||||
}): AppBskyFeedDefs.ThreadgateView {
|
|
||||||
const record: AppBskyFeedThreadgate.Record = {
|
|
||||||
$type: 'app.bsky.feed.threadgate',
|
|
||||||
post: postUri,
|
|
||||||
allow: undefined,
|
|
||||||
hiddenReplies,
|
|
||||||
createdAt: new Date().toISOString(),
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
$type: 'app.bsky.feed.defs#threadgateView',
|
|
||||||
uri: postUri,
|
|
||||||
record,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import {AppBskyFeedThreadgate} from '@atproto/api'
|
||||||
|
|
||||||
type StateContext = {
|
type StateContext = {
|
||||||
uris: Set<string>
|
uris: Set<string>
|
||||||
|
@ -67,3 +68,18 @@ export function useThreadgateHiddenReplyUris() {
|
||||||
export function useThreadgateHiddenReplyUrisAPI() {
|
export function useThreadgateHiddenReplyUrisAPI() {
|
||||||
return React.useContext(ApiContext)
|
return React.useContext(ApiContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useMergedThreadgateHiddenReplies({
|
||||||
|
threadgateRecord,
|
||||||
|
}: {
|
||||||
|
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||||
|
}) {
|
||||||
|
const {uris, recentlyUnhiddenUris} = useThreadgateHiddenReplyUris()
|
||||||
|
return React.useMemo(() => {
|
||||||
|
const set = new Set([...(threadgateRecord?.hiddenReplies || []), ...uris])
|
||||||
|
for (const uri of recentlyUnhiddenUris) {
|
||||||
|
set.delete(uri)
|
||||||
|
}
|
||||||
|
return set
|
||||||
|
}, [uris, recentlyUnhiddenUris, threadgateRecord])
|
||||||
|
}
|
||||||
|
|
|
@ -3,12 +3,7 @@ import {StyleSheet, useWindowDimensions, View} from 'react-native'
|
||||||
import {runOnJS} from 'react-native-reanimated'
|
import {runOnJS} from 'react-native-reanimated'
|
||||||
import Animated from 'react-native-reanimated'
|
import Animated from 'react-native-reanimated'
|
||||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||||
import {
|
import {AppBskyFeedDefs, AppBskyFeedThreadgate} from '@atproto/api'
|
||||||
AppBskyFeedDefs,
|
|
||||||
AppBskyFeedPost,
|
|
||||||
AppBskyFeedThreadgate,
|
|
||||||
AtUri,
|
|
||||||
} from '@atproto/api'
|
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
@ -28,9 +23,9 @@ import {
|
||||||
usePostThreadQuery,
|
usePostThreadQuery,
|
||||||
} from '#/state/queries/post-thread'
|
} from '#/state/queries/post-thread'
|
||||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||||
import {useThreadgateRecordQuery} from '#/state/queries/threadgate'
|
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useComposerControls} from '#/state/shell'
|
import {useComposerControls} from '#/state/shell'
|
||||||
|
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||||
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
|
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
|
||||||
import {useMinimalShellFabTransform} from 'lib/hooks/useMinimalShellTransform'
|
import {useMinimalShellFabTransform} from 'lib/hooks/useMinimalShellTransform'
|
||||||
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
||||||
|
@ -108,7 +103,7 @@ export function PostThread({uri}: {uri: string | undefined}) {
|
||||||
isError: isThreadError,
|
isError: isThreadError,
|
||||||
error: threadError,
|
error: threadError,
|
||||||
refetch,
|
refetch,
|
||||||
data: thread,
|
data: {thread, threadgate} = {},
|
||||||
} = usePostThreadQuery(uri)
|
} = usePostThreadQuery(uri)
|
||||||
|
|
||||||
const treeView = React.useMemo(
|
const treeView = React.useMemo(
|
||||||
|
@ -119,26 +114,11 @@ export function PostThread({uri}: {uri: string | undefined}) {
|
||||||
)
|
)
|
||||||
const rootPost = thread?.type === 'post' ? thread.post : undefined
|
const rootPost = thread?.type === 'post' ? thread.post : undefined
|
||||||
const rootPostRecord = thread?.type === 'post' ? thread.record : undefined
|
const rootPostRecord = thread?.type === 'post' ? thread.record : undefined
|
||||||
const replyRef =
|
const threadgateRecord = threadgate?.record as
|
||||||
rootPostRecord && AppBskyFeedPost.isRecord(rootPostRecord)
|
|
||||||
? rootPostRecord.reply
|
|
||||||
: undefined
|
|
||||||
const rootPostUri = replyRef ? replyRef.root.uri : rootPost?.uri
|
|
||||||
|
|
||||||
const isOP =
|
|
||||||
currentAccount &&
|
|
||||||
rootPostUri &&
|
|
||||||
currentAccount?.did === new AtUri(rootPostUri).host
|
|
||||||
const initialThreadgateRecord = rootPost?.threadgate?.record as
|
|
||||||
| AppBskyFeedThreadgate.Record
|
| AppBskyFeedThreadgate.Record
|
||||||
| undefined
|
| undefined
|
||||||
const {data: threadgateRecord} = useThreadgateRecordQuery({
|
const threadgateHiddenReplies = useMergedThreadgateHiddenReplies({
|
||||||
/**
|
threadgateRecord,
|
||||||
* If the user is the OP and we have a root post, fetch the threadgate.
|
|
||||||
*/
|
|
||||||
enabled: Boolean(isOP && rootPostUri),
|
|
||||||
postUri: rootPostUri,
|
|
||||||
initialData: initialThreadgateRecord,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const moderationOpts = useModerationOpts()
|
const moderationOpts = useModerationOpts()
|
||||||
|
@ -194,9 +174,6 @@ export function PostThread({uri}: {uri: string | undefined}) {
|
||||||
const skeleton = React.useMemo(() => {
|
const skeleton = React.useMemo(() => {
|
||||||
const threadViewPrefs = preferences?.threadViewPrefs
|
const threadViewPrefs = preferences?.threadViewPrefs
|
||||||
if (!threadViewPrefs || !thread) return null
|
if (!threadViewPrefs || !thread) return null
|
||||||
const threadgateRecordHiddenReplies = new Set<string>(
|
|
||||||
threadgateRecord?.hiddenReplies || [],
|
|
||||||
)
|
|
||||||
|
|
||||||
return createThreadSkeleton(
|
return createThreadSkeleton(
|
||||||
sortThread(
|
sortThread(
|
||||||
|
@ -205,13 +182,13 @@ export function PostThread({uri}: {uri: string | undefined}) {
|
||||||
threadModerationCache,
|
threadModerationCache,
|
||||||
currentDid,
|
currentDid,
|
||||||
justPostedUris,
|
justPostedUris,
|
||||||
threadgateRecordHiddenReplies,
|
threadgateHiddenReplies,
|
||||||
),
|
),
|
||||||
currentDid,
|
currentDid,
|
||||||
treeView,
|
treeView,
|
||||||
threadModerationCache,
|
threadModerationCache,
|
||||||
hiddenRepliesState !== HiddenRepliesState.Hide,
|
hiddenRepliesState !== HiddenRepliesState.Hide,
|
||||||
threadgateRecordHiddenReplies,
|
threadgateHiddenReplies,
|
||||||
)
|
)
|
||||||
}, [
|
}, [
|
||||||
thread,
|
thread,
|
||||||
|
@ -221,7 +198,7 @@ export function PostThread({uri}: {uri: string | undefined}) {
|
||||||
threadModerationCache,
|
threadModerationCache,
|
||||||
hiddenRepliesState,
|
hiddenRepliesState,
|
||||||
justPostedUris,
|
justPostedUris,
|
||||||
threadgateRecord,
|
threadgateHiddenReplies,
|
||||||
])
|
])
|
||||||
|
|
||||||
const error = React.useMemo(() => {
|
const error = React.useMemo(() => {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import {useLanguagePrefs} from '#/state/preferences'
|
||||||
import {useOpenLink} from '#/state/preferences/in-app-browser'
|
import {useOpenLink} from '#/state/preferences/in-app-browser'
|
||||||
import {ThreadPost} from '#/state/queries/post-thread'
|
import {ThreadPost} from '#/state/queries/post-thread'
|
||||||
import {useComposerControls} from '#/state/shell/composer'
|
import {useComposerControls} from '#/state/shell/composer'
|
||||||
|
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||||
import {MAX_POST_LINES} from 'lib/constants'
|
import {MAX_POST_LINES} from 'lib/constants'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||||
|
@ -206,24 +207,22 @@ let PostThreadItemLoaded = ({
|
||||||
return makeProfileLink(post.author, 'post', urip.rkey, 'reposted-by')
|
return makeProfileLink(post.author, 'post', urip.rkey, 'reposted-by')
|
||||||
}, [post.uri, post.author])
|
}, [post.uri, post.author])
|
||||||
const repostsTitle = _(msg`Reposts of this post`)
|
const repostsTitle = _(msg`Reposts of this post`)
|
||||||
|
const threadgateHiddenReplies = useMergedThreadgateHiddenReplies({
|
||||||
|
threadgateRecord,
|
||||||
|
})
|
||||||
const additionalPostAlerts: AppModerationCause[] = React.useMemo(() => {
|
const additionalPostAlerts: AppModerationCause[] = React.useMemo(() => {
|
||||||
const isPostHiddenByThreadgate = threadgateRecord?.hiddenReplies?.includes(
|
const isPostHiddenByThreadgate = threadgateHiddenReplies.has(post.uri)
|
||||||
post.uri,
|
const isControlledByViewer = new AtUri(rootUri).host === currentAccount?.did
|
||||||
)
|
return isControlledByViewer && isPostHiddenByThreadgate
|
||||||
const isControlledByViewer =
|
|
||||||
threadgateRecord &&
|
|
||||||
new AtUri(threadgateRecord.post).host === currentAccount?.did
|
|
||||||
if (!isControlledByViewer) return []
|
|
||||||
return threadgateRecord && isPostHiddenByThreadgate
|
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
type: 'reply-hidden',
|
type: 'reply-hidden',
|
||||||
source: {type: 'user', did: new AtUri(threadgateRecord.post).host},
|
source: {type: 'user', did: currentAccount?.did},
|
||||||
priority: 6,
|
priority: 6,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []
|
: []
|
||||||
}, [post, threadgateRecord, currentAccount?.did])
|
}, [post, currentAccount?.did, threadgateHiddenReplies, rootUri])
|
||||||
const quotesHref = React.useMemo(() => {
|
const quotesHref = React.useMemo(() => {
|
||||||
const urip = new AtUri(post.uri)
|
const urip = new AtUri(post.uri)
|
||||||
return makeProfileLink(post.author, 'post', urip.rkey, 'quotes')
|
return makeProfileLink(post.author, 'post', urip.rkey, 'quotes')
|
||||||
|
|
|
@ -22,7 +22,7 @@ import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow'
|
||||||
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useComposerControls} from '#/state/shell/composer'
|
import {useComposerControls} from '#/state/shell/composer'
|
||||||
import {useThreadgateHiddenReplyUris} from '#/state/threadgate-hidden-replies'
|
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||||
import {isReasonFeedSource, ReasonFeedSource} from 'lib/api/feed/types'
|
import {isReasonFeedSource, ReasonFeedSource} from 'lib/api/feed/types'
|
||||||
import {MAX_POST_LINES} from 'lib/constants'
|
import {MAX_POST_LINES} from 'lib/constants'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
|
@ -227,6 +227,10 @@ let FeedItemInner = ({
|
||||||
AppBskyFeedDefs.isReasonRepost(reason) &&
|
AppBskyFeedDefs.isReasonRepost(reason) &&
|
||||||
reason.by.did === currentAccount?.did
|
reason.by.did === currentAccount?.did
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If `post[0]` in this slice is the actual root post (not an orphan thread),
|
||||||
|
* then we may have a threadgate record to reference
|
||||||
|
*/
|
||||||
const threadgateRecord = AppBskyFeedThreadgate.isRecord(
|
const threadgateRecord = AppBskyFeedThreadgate.isRecord(
|
||||||
rootPost.threadgate?.record,
|
rootPost.threadgate?.record,
|
||||||
)
|
)
|
||||||
|
@ -422,41 +426,26 @@ let PostContent = ({
|
||||||
const [limitLines, setLimitLines] = useState(
|
const [limitLines, setLimitLines] = useState(
|
||||||
() => countLines(richText.text) >= MAX_POST_LINES,
|
() => countLines(richText.text) >= MAX_POST_LINES,
|
||||||
)
|
)
|
||||||
const {uris: hiddenReplyUris, recentlyUnhiddenUris} =
|
const threadgateHiddenReplies = useMergedThreadgateHiddenReplies({
|
||||||
useThreadgateHiddenReplyUris()
|
threadgateRecord,
|
||||||
|
})
|
||||||
const additionalPostAlerts: AppModerationCause[] = React.useMemo(() => {
|
const additionalPostAlerts: AppModerationCause[] = React.useMemo(() => {
|
||||||
const isPostHiddenByHiddenReplyCache = hiddenReplyUris.has(post.uri)
|
const isPostHiddenByThreadgate = threadgateHiddenReplies.has(post.uri)
|
||||||
const isPostHiddenByThreadgate =
|
const rootPostUri = AppBskyFeedPost.isRecord(post.record)
|
||||||
!recentlyUnhiddenUris.has(post.uri) &&
|
? post.record?.reply?.root?.uri || post.uri
|
||||||
!!threadgateRecord?.hiddenReplies?.includes(post.uri)
|
: undefined
|
||||||
const isHidden = isPostHiddenByHiddenReplyCache || isPostHiddenByThreadgate
|
|
||||||
const isControlledByViewer =
|
const isControlledByViewer =
|
||||||
isPostHiddenByHiddenReplyCache ||
|
rootPostUri && new AtUri(rootPostUri).host === currentAccount?.did
|
||||||
(threadgateRecord &&
|
return isControlledByViewer && isPostHiddenByThreadgate
|
||||||
new AtUri(threadgateRecord.post).host === currentAccount?.did)
|
|
||||||
if (!isControlledByViewer) return []
|
|
||||||
const alertSource =
|
|
||||||
threadgateRecord && isPostHiddenByThreadgate
|
|
||||||
? new AtUri(threadgateRecord.post).host
|
|
||||||
: isPostHiddenByHiddenReplyCache
|
|
||||||
? currentAccount?.did
|
|
||||||
: undefined
|
|
||||||
return isHidden && alertSource
|
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
type: 'reply-hidden',
|
type: 'reply-hidden',
|
||||||
source: {type: 'user', did: alertSource},
|
source: {type: 'user', did: currentAccount?.did},
|
||||||
priority: 6,
|
priority: 6,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []
|
: []
|
||||||
}, [
|
}, [post, currentAccount?.did, threadgateHiddenReplies])
|
||||||
post,
|
|
||||||
hiddenReplyUris,
|
|
||||||
recentlyUnhiddenUris,
|
|
||||||
threadgateRecord,
|
|
||||||
currentAccount?.did,
|
|
||||||
])
|
|
||||||
|
|
||||||
const onPressShowMore = React.useCallback(() => {
|
const onPressShowMore = React.useCallback(() => {
|
||||||
setLimitLines(false)
|
setLimitLines(false)
|
||||||
|
|
|
@ -37,7 +37,7 @@ import {useToggleQuoteDetachmentMutation} from '#/state/queries/postgate'
|
||||||
import {getMaybeDetachedQuoteEmbed} from '#/state/queries/postgate/util'
|
import {getMaybeDetachedQuoteEmbed} from '#/state/queries/postgate/util'
|
||||||
import {useToggleReplyVisibilityMutation} from '#/state/queries/threadgate'
|
import {useToggleReplyVisibilityMutation} from '#/state/queries/threadgate'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useThreadgateHiddenReplyUris} from '#/state/threadgate-hidden-replies'
|
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||||
import {getCurrentRoute} from 'lib/routes/helpers'
|
import {getCurrentRoute} from 'lib/routes/helpers'
|
||||||
import {shareUrl} from 'lib/sharing'
|
import {shareUrl} from 'lib/sharing'
|
||||||
import {toShareUrl} from 'lib/strings/url-helpers'
|
import {toShareUrl} from 'lib/strings/url-helpers'
|
||||||
|
@ -124,8 +124,6 @@ let PostDropdownBtn = ({
|
||||||
const hideReplyConfirmControl = useDialogControl()
|
const hideReplyConfirmControl = useDialogControl()
|
||||||
const {mutateAsync: toggleReplyVisibility} =
|
const {mutateAsync: toggleReplyVisibility} =
|
||||||
useToggleReplyVisibilityMutation()
|
useToggleReplyVisibilityMutation()
|
||||||
const {uris: hiddenReplies, recentlyUnhiddenUris} =
|
|
||||||
useThreadgateHiddenReplyUris()
|
|
||||||
|
|
||||||
const postUri = post.uri
|
const postUri = post.uri
|
||||||
const postCid = post.cid
|
const postCid = post.cid
|
||||||
|
@ -147,10 +145,10 @@ let PostDropdownBtn = ({
|
||||||
const isPostHidden = hiddenPosts && hiddenPosts.includes(postUri)
|
const isPostHidden = hiddenPosts && hiddenPosts.includes(postUri)
|
||||||
const isAuthor = postAuthor.did === currentAccount?.did
|
const isAuthor = postAuthor.did === currentAccount?.did
|
||||||
const isRootPostAuthor = new AtUri(rootUri).host === currentAccount?.did
|
const isRootPostAuthor = new AtUri(rootUri).host === currentAccount?.did
|
||||||
const isReplyHiddenByThreadgate =
|
const threadgateHiddenReplies = useMergedThreadgateHiddenReplies({
|
||||||
hiddenReplies.has(postUri) ||
|
threadgateRecord,
|
||||||
(!recentlyUnhiddenUris.has(postUri) &&
|
})
|
||||||
threadgateRecord?.hiddenReplies?.includes(postUri))
|
const isReplyHiddenByThreadgate = threadgateHiddenReplies.has(postUri)
|
||||||
|
|
||||||
const {mutateAsync: toggleQuoteDetachment, isPending} =
|
const {mutateAsync: toggleQuoteDetachment, isPending} =
|
||||||
useToggleQuoteDetachmentMutation()
|
useToggleQuoteDetachmentMutation()
|
||||||
|
|
Loading…
Reference in New Issue