Refactor client-side hidden
This commit is contained in:
@@ -9,11 +9,7 @@ import {ScrollProvider} from '#/lib/ScrollContext'
|
|||||||
import {cleanError} from '#/lib/strings/errors'
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
import {isNative} from '#/platform/detection'
|
import {isNative} from '#/platform/detection'
|
||||||
import {useThreadPreferences} from '#/state/queries/preferences/useThreadPreferences'
|
import {useThreadPreferences} from '#/state/queries/preferences/useThreadPreferences'
|
||||||
import {
|
import {type ThreadItem, usePostThread} from '#/state/queries/usePostThread'
|
||||||
HiddenReplyKind,
|
|
||||||
type ThreadItem,
|
|
||||||
usePostThread,
|
|
||||||
} from '#/state/queries/usePostThread'
|
|
||||||
import {type OnPostSuccessData} from '#/state/shell/composer'
|
import {type OnPostSuccessData} from '#/state/shell/composer'
|
||||||
import {PostThreadComposePrompt} from '#/view/com/post-thread/PostThreadComposePrompt'
|
import {PostThreadComposePrompt} from '#/view/com/post-thread/PostThreadComposePrompt'
|
||||||
import {PostThreadShowHiddenReplies} from '#/view/com/post-thread/PostThreadShowHiddenReplies'
|
import {PostThreadShowHiddenReplies} from '#/view/com/post-thread/PostThreadShowHiddenReplies'
|
||||||
@@ -53,22 +49,16 @@ export function Inner({uri}: {uri: string | undefined}) {
|
|||||||
setTreeViewEnabled,
|
setTreeViewEnabled,
|
||||||
} = useThreadPreferences()
|
} = useThreadPreferences()
|
||||||
|
|
||||||
const [shownHiddenReplyKinds, setShownHiddenReplyKinds] = useState<
|
const {isFetching, error, data, refetch, insertReplies, showHiddenReplies} =
|
||||||
Set<HiddenReplyKind>
|
usePostThread({
|
||||||
>(new Set())
|
enabled: isThreadPreferencesLoaded,
|
||||||
|
params: {
|
||||||
const {isFetching, error, data, refetch, insertReplies} = usePostThread({
|
anchor: uri,
|
||||||
enabled: isThreadPreferencesLoaded,
|
sort: sortReplies,
|
||||||
params: {
|
view: treeViewEnabled ? 'tree' : 'linear',
|
||||||
anchor: uri,
|
prioritizeFollowedUsers,
|
||||||
sort: sortReplies,
|
},
|
||||||
view: treeViewEnabled ? 'tree' : 'linear',
|
})
|
||||||
prioritizeFollowedUsers,
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
shownHiddenReplyKinds,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const optimisticOnPostReply = (data: OnPostSuccessData) => {
|
const optimisticOnPostReply = (data: OnPostSuccessData) => {
|
||||||
if (data) {
|
if (data) {
|
||||||
@@ -242,9 +232,7 @@ export function Inner({uri}: {uri: string | undefined}) {
|
|||||||
item={item}
|
item={item}
|
||||||
threadgateRecord={data?.threadgate?.record ?? undefined}
|
threadgateRecord={data?.threadgate?.record ?? undefined}
|
||||||
overrides={{
|
overrides={{
|
||||||
moderation:
|
moderation: showHiddenReplies && item.depth > 0,
|
||||||
shownHiddenReplyKinds.has(HiddenReplyKind.Hidden) &&
|
|
||||||
item.depth > 0,
|
|
||||||
}}
|
}}
|
||||||
onPostSuccess={optimisticOnPostReply}
|
onPostSuccess={optimisticOnPostReply}
|
||||||
/>
|
/>
|
||||||
@@ -255,9 +243,7 @@ export function Inner({uri}: {uri: string | undefined}) {
|
|||||||
item={item}
|
item={item}
|
||||||
threadgateRecord={data?.threadgate?.record ?? undefined}
|
threadgateRecord={data?.threadgate?.record ?? undefined}
|
||||||
overrides={{
|
overrides={{
|
||||||
moderation:
|
moderation: showHiddenReplies && item.depth > 0,
|
||||||
shownHiddenReplyKinds.has(HiddenReplyKind.Muted) &&
|
|
||||||
item.depth > 0,
|
|
||||||
}}
|
}}
|
||||||
onPostSuccess={optimisticOnPostReply}
|
onPostSuccess={optimisticOnPostReply}
|
||||||
/>
|
/>
|
||||||
@@ -305,10 +291,8 @@ export function Inner({uri}: {uri: string | undefined}) {
|
|||||||
} else if (item.type === 'showHiddenReplies') {
|
} else if (item.type === 'showHiddenReplies') {
|
||||||
return (
|
return (
|
||||||
<PostThreadShowHiddenReplies
|
<PostThreadShowHiddenReplies
|
||||||
type={item.kind === 'muted' ? 'muted' : 'hidden'}
|
type="hidden"
|
||||||
onPress={() =>
|
onPress={() => item.onLoad()}
|
||||||
setShownHiddenReplyKinds(kinds => new Set([...kinds, item.kind]))
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
} else if (item.type === 'skeleton') {
|
} else if (item.type === 'skeleton') {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {useMemo} from 'react'
|
import {useCallback, useMemo, useRef, useState} from 'react'
|
||||||
import {useQuery, useQueryClient} from '@tanstack/react-query'
|
import {useQuery, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
import {traverse} from '#/state/queries/usePostThread/traversal'
|
import {traverse} from '#/state/queries/usePostThread/traversal'
|
||||||
import {
|
import {
|
||||||
createPostThreadQueryKey,
|
createPostThreadQueryKey,
|
||||||
HiddenReplyKind,
|
|
||||||
type UsePostThreadProps,
|
type UsePostThreadProps,
|
||||||
} from '#/state/queries/usePostThread/types'
|
} from '#/state/queries/usePostThread/types'
|
||||||
import {getThreadgateRecord} from '#/state/queries/usePostThread/utils'
|
import {getThreadgateRecord} from '#/state/queries/usePostThread/utils'
|
||||||
@@ -21,7 +20,6 @@ export * from '#/state/queries/usePostThread/types'
|
|||||||
export function usePostThread({
|
export function usePostThread({
|
||||||
enabled: isEnabled,
|
enabled: isEnabled,
|
||||||
params,
|
params,
|
||||||
state,
|
|
||||||
}: UsePostThreadProps) {
|
}: UsePostThreadProps) {
|
||||||
const qc = useQueryClient()
|
const qc = useQueryClient()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
@@ -34,6 +32,9 @@ export function usePostThread({
|
|||||||
params,
|
params,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const hasHiddenReplies = useRef(false)
|
||||||
|
const [showHiddenReplies, setShowHiddenReplies] = useState(false)
|
||||||
|
|
||||||
const query = useQuery({
|
const query = useQuery({
|
||||||
enabled,
|
enabled,
|
||||||
queryKey,
|
queryKey,
|
||||||
@@ -50,10 +51,17 @@ export function usePostThread({
|
|||||||
},
|
},
|
||||||
placeholderData() {
|
placeholderData() {
|
||||||
if (!params.anchor) return
|
if (!params.anchor) return
|
||||||
|
|
||||||
const placeholder = getThreadPlaceholder(qc, params.anchor)
|
const placeholder = getThreadPlaceholder(qc, params.anchor)
|
||||||
|
|
||||||
if (placeholder) {
|
if (placeholder) {
|
||||||
return {thread: [placeholder], hasHiddenReplies: false}
|
return {thread: [placeholder], hasHiddenReplies: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return empty data here so that `isPlaceholderData` is always true,
|
||||||
|
* which we'll use to insert skeletons.
|
||||||
|
*/
|
||||||
return {thread: [], hasHiddenReplies: false}
|
return {thread: [], hasHiddenReplies: false}
|
||||||
},
|
},
|
||||||
select(data) {
|
select(data) {
|
||||||
@@ -68,7 +76,13 @@ export function usePostThread({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO map over pages, just like feeds
|
if (query?.data?.hasHiddenReplies) {
|
||||||
|
hasHiddenReplies.current = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadHiddenReplies = useCallback(async () => {
|
||||||
|
setShowHiddenReplies(true)
|
||||||
|
}, [setShowHiddenReplies])
|
||||||
|
|
||||||
const items = useMemo(() => {
|
const items = useMemo(() => {
|
||||||
return traverse(query.data?.thread || [], {
|
return traverse(query.data?.thread || [], {
|
||||||
@@ -77,25 +91,21 @@ export function usePostThread({
|
|||||||
),
|
),
|
||||||
moderationOpts: moderationOpts!,
|
moderationOpts: moderationOpts!,
|
||||||
hasSession,
|
hasSession,
|
||||||
showMuted: state.shownHiddenReplyKinds.has(HiddenReplyKind.Muted),
|
|
||||||
showHidden: state.shownHiddenReplyKinds.has(HiddenReplyKind.Hidden),
|
|
||||||
view: params.view,
|
view: params.view,
|
||||||
|
hasHiddenReplies: hasHiddenReplies.current,
|
||||||
|
showHiddenReplies,
|
||||||
|
loadHiddenReplies,
|
||||||
})
|
})
|
||||||
}, [
|
}, [
|
||||||
query.data,
|
query.data,
|
||||||
mergeThreadgateHiddenReplies,
|
mergeThreadgateHiddenReplies,
|
||||||
moderationOpts,
|
moderationOpts,
|
||||||
hasSession,
|
hasSession,
|
||||||
state.shownHiddenReplyKinds,
|
|
||||||
params.view,
|
params.view,
|
||||||
|
showHiddenReplies,
|
||||||
|
loadHiddenReplies,
|
||||||
])
|
])
|
||||||
|
|
||||||
const mutator = createCacheMutator({
|
|
||||||
params,
|
|
||||||
queryKey,
|
|
||||||
queryClient: qc,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (query.isPlaceholderData) {
|
if (query.isPlaceholderData) {
|
||||||
const anchor = items.at(0)
|
const anchor = items.at(0)
|
||||||
const skeletonReplies =
|
const skeletonReplies =
|
||||||
@@ -128,12 +138,27 @@ export function usePostThread({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
const mutator = useMemo(
|
||||||
...query,
|
() =>
|
||||||
data: {
|
createCacheMutator({
|
||||||
items,
|
params,
|
||||||
threadgate: query.data?.threadgate,
|
queryKey,
|
||||||
},
|
queryClient: qc,
|
||||||
insertReplies: mutator.insertReplies,
|
}),
|
||||||
}
|
[qc, params, queryKey],
|
||||||
|
)
|
||||||
|
|
||||||
|
return useMemo(
|
||||||
|
() => ({
|
||||||
|
...query,
|
||||||
|
data: {
|
||||||
|
items,
|
||||||
|
threadgate: query.data?.threadgate,
|
||||||
|
},
|
||||||
|
hasHiddenReplies: hasHiddenReplies.current,
|
||||||
|
showHiddenReplies,
|
||||||
|
insertReplies: mutator.insertReplies,
|
||||||
|
}),
|
||||||
|
[query, items, mutator.insertReplies, showHiddenReplies],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
HiddenReplyKind,
|
|
||||||
type PostThreadParams,
|
type PostThreadParams,
|
||||||
type ThreadItem,
|
type ThreadItem,
|
||||||
type TraversalMetadata,
|
type TraversalMetadata,
|
||||||
@@ -24,21 +23,22 @@ export function traverse(
|
|||||||
threadgateHiddenReplies,
|
threadgateHiddenReplies,
|
||||||
moderationOpts,
|
moderationOpts,
|
||||||
hasSession,
|
hasSession,
|
||||||
showMuted,
|
|
||||||
showHidden,
|
|
||||||
view,
|
view,
|
||||||
|
hasHiddenReplies,
|
||||||
|
showHiddenReplies,
|
||||||
|
loadHiddenReplies,
|
||||||
}: {
|
}: {
|
||||||
threadgateHiddenReplies: Set<string>
|
threadgateHiddenReplies: Set<string>
|
||||||
moderationOpts: ModerationOpts
|
moderationOpts: ModerationOpts
|
||||||
hasSession: boolean
|
hasSession: boolean
|
||||||
showMuted: boolean
|
|
||||||
showHidden: boolean
|
|
||||||
view: PostThreadParams['view']
|
view: PostThreadParams['view']
|
||||||
|
hasHiddenReplies: boolean
|
||||||
|
showHiddenReplies: boolean
|
||||||
|
loadHiddenReplies: () => Promise<void>
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
const items: ThreadItem[] = []
|
const items: ThreadItem[] = []
|
||||||
const hidden: ThreadItem[] = []
|
const hidden: ThreadItem[] = []
|
||||||
const muted: ThreadItem[] = []
|
|
||||||
const metadatas = new Map<string, TraversalMetadata>()
|
const metadatas = new Map<string, TraversalMetadata>()
|
||||||
|
|
||||||
traversal: for (let i = 0; i < thread.length; i++) {
|
traversal: for (let i = 0; i < thread.length; i++) {
|
||||||
@@ -178,16 +178,13 @@ export function traverse(
|
|||||||
* Moderated in some way, we're going to walk children
|
* Moderated in some way, we're going to walk children
|
||||||
*/
|
*/
|
||||||
const parent = post
|
const parent = post
|
||||||
const parentMod = postMod
|
|
||||||
const parentIsTopLevelReply = parent.depth === 1
|
const parentIsTopLevelReply = parent.depth === 1
|
||||||
const sortArray = parentMod.muted ? muted : hidden
|
|
||||||
|
|
||||||
// get sub tree
|
// get sub tree
|
||||||
const branch = getBranch(thread, i, item.depth)
|
const branch = getBranch(thread, i, item.depth)
|
||||||
|
|
||||||
if (parentIsTopLevelReply) {
|
if (parentIsTopLevelReply) {
|
||||||
// push branch anchor into sorted array
|
// push branch anchor into sorted array
|
||||||
sortArray.push(parent)
|
hidden.push(parent)
|
||||||
// skip branch anchor in branch traversal
|
// skip branch anchor in branch traversal
|
||||||
const startIndex = branch.start + 1
|
const startIndex = branch.start + 1
|
||||||
|
|
||||||
@@ -238,7 +235,7 @@ export function traverse(
|
|||||||
) {
|
) {
|
||||||
ci = getBranch(thread, ci, child.depth).end
|
ci = getBranch(thread, ci, child.depth).end
|
||||||
} else {
|
} else {
|
||||||
sortArray.push(childPost)
|
hidden.push(childPost)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
@@ -259,36 +256,14 @@ export function traverse(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hidden.length) {
|
if (hidden.length || hasHiddenReplies) {
|
||||||
if (showHidden) {
|
if (showHiddenReplies) {
|
||||||
items.push(...hidden)
|
items.push(...hidden)
|
||||||
|
|
||||||
if (muted.length) {
|
|
||||||
if (showMuted) {
|
|
||||||
items.push(...muted)
|
|
||||||
} else {
|
|
||||||
items.push({
|
|
||||||
type: 'showHiddenReplies',
|
|
||||||
key: 'showMutedReplies',
|
|
||||||
kind: HiddenReplyKind.Muted,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
items.push({
|
items.push({
|
||||||
type: 'showHiddenReplies',
|
type: 'showHiddenReplies',
|
||||||
key: 'showHiddenReplies',
|
key: 'showHiddenReplies',
|
||||||
kind: HiddenReplyKind.Hidden,
|
onLoad: loadHiddenReplies,
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (muted.length) {
|
|
||||||
if (showMuted) {
|
|
||||||
items.push(...muted)
|
|
||||||
} else {
|
|
||||||
items.push({
|
|
||||||
type: 'showHiddenReplies',
|
|
||||||
key: 'showMutedReplies',
|
|
||||||
kind: HiddenReplyKind.Muted,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,14 +22,6 @@ export type PostThreadParams = Pick<
|
|||||||
export type UsePostThreadProps = {
|
export type UsePostThreadProps = {
|
||||||
enabled?: boolean
|
enabled?: boolean
|
||||||
params: PostThreadParams
|
params: PostThreadParams
|
||||||
state: {
|
|
||||||
shownHiddenReplyKinds: Set<HiddenReplyKind>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum HiddenReplyKind {
|
|
||||||
Hidden = 'hidden',
|
|
||||||
Muted = 'muted',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ThreadItem =
|
export type ThreadItem =
|
||||||
@@ -82,7 +74,7 @@ export type ThreadItem =
|
|||||||
| {
|
| {
|
||||||
type: 'showHiddenReplies'
|
type: 'showHiddenReplies'
|
||||||
key: string
|
key: string
|
||||||
kind: HiddenReplyKind
|
onLoad: () => Promise<void>
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: 'readMore'
|
type: 'readMore'
|
||||||
|
|||||||
Reference in New Issue
Block a user