Fix live comments behavior on paginated comments and threads (#2334)

* livecomments: patches for paginated comments; broader ViewMoreReplies component

live comments:
- don't show the thread button for thread comments that are shown as full items (top level)
- don't try to count/inject on paginated comments, just show the live comments dot
- dedupe new comments being fetched with already existing comments, useful for just showing the dot, but not the button

comments:
- live comments dot now appears on both paginated and bottomed out comments
-- merge ViewAllReplies with ReplyToAnotherPage

* fix thread comment recognition, now based on depth
This commit is contained in:
soxa 2025-07-27 01:06:22 +02:00 committed by GitHub
parent ef1c586231
commit a4a0fdb060
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 27 additions and 28 deletions

View File

@ -261,7 +261,7 @@ export default function Comment ({
</div> </div>
{collapse !== 'yep' && ( {collapse !== 'yep' && (
bottomedOut bottomedOut
? <div className={styles.children}><div className={classNames(styles.comment, 'mt-3')}><ReplyOnAnotherPage item={item} /></div></div> ? <div className={styles.children}><div className={classNames(styles.comment, 'mt-3 pb-2')}><ViewMoreReplies item={item} navigateRoot /></div></div>
: ( : (
<div className={styles.children}> <div className={styles.children}>
{item.outlawed && !me?.privates?.wildWestMode {item.outlawed && !me?.privates?.wildWestMode
@ -281,7 +281,11 @@ export default function Comment ({
{item.comments.comments.map((item) => ( {item.comments.comments.map((item) => (
<Comment depth={depth + 1} key={item.id} item={item} rootLastCommentAt={rootLastCommentAt} /> <Comment depth={depth + 1} key={item.id} item={item} rootLastCommentAt={rootLastCommentAt} />
))} ))}
{item.comments.comments.length < item.nDirectComments && <ViewAllReplies id={item.id} nhas={item.ncomments} />} {item.comments.comments.length < item.nDirectComments && (
<div className={`d-block ${styles.comment} pb-2 ps-3`}>
<ViewMoreReplies item={item} />
</div>
)}
</> </>
) )
: null} : null}
@ -294,31 +298,24 @@ export default function Comment ({
) )
} }
export function ViewAllReplies ({ id, nshown, nhas }) { export function ViewMoreReplies ({ item, navigateRoot = false }) {
const text = `view all ${nhas} replies`
return (
<div className={`d-block fw-bold ${styles.comment} pb-2 ps-3`}>
<Link href={`/items/${id}`} as={`/items/${id}`} className='text-muted'>
{text}
</Link>
</div>
)
}
function ReplyOnAnotherPage ({ item }) {
const root = useRoot() const root = useRoot()
const rootId = commentSubTreeRootId(item, root)
const { cache } = useApolloClient() const { cache } = useApolloClient()
const id = navigateRoot ? commentSubTreeRootId(item, root) : item.id
let text = 'reply on another page' const href = `/items/${id}` + (navigateRoot ? '' : `?commentId=${item.id}`)
if (item.ncomments > 0) {
text = `view all ${item.ncomments} replies` const text = navigateRoot && item.ncomments === 0
} ? 'reply on another page'
: `view all ${item.ncomments} replies`
return ( return (
<Link <Link
href={href}
as={`/items/${id}`}
className='fw-bold d-flex align-items-center gap-2 text-muted'
onClick={() => { onClick={() => {
if (!item.newComments?.length) return
// clear new comments going to another page // clear new comments going to another page
cache.writeFragment({ cache.writeFragment({
id: `Item:${item.id}`, id: `Item:${item.id}`,
@ -331,9 +328,6 @@ function ReplyOnAnotherPage ({ item }) {
} }
}) })
}} }}
href={`/items/${rootId}?commentId=${item.id}`}
as={`/items/${rootId}`}
className='pb-2 fw-bold d-flex align-items-center gap-2 text-muted'
> >
{text} {text}
{item.newComments?.length > 0 && <div className={styles.newCommentDot} />} {item.newComments?.length > 0 && <div className={styles.newCommentDot} />}

View File

@ -74,6 +74,10 @@ function traverseNewComments (client, item, onLevel, currentDepth, inSubtree) {
// if we're at the depth limit, stop traversing, we've reached the bottom of the visible thread // if we're at the depth limit, stop traversing, we've reached the bottom of the visible thread
if (currentDepth >= COMMENT_DEPTH_LIMIT) return if (currentDepth >= COMMENT_DEPTH_LIMIT) return
// if the current item shows less comments than its nDirectComments, it's paginated
// we don't want to count/inject new comments in paginated items, as they shouldn't be visible
if (item.comments?.comments?.length < item.nDirectComments) return
if (item.newComments && item.newComments.length > 0) { if (item.newComments && item.newComments.length > 0) {
const dedupedNewComments = dedupeNewComments(item.newComments, item.comments?.comments) const dedupedNewComments = dedupeNewComments(item.newComments, item.comments?.comments)
@ -161,8 +165,8 @@ export function ShowNewComments ({ topLevel, item, sort, depth = 0 }) {
const client = useApolloClient() const client = useApolloClient()
const ref = useRef(null) const ref = useRef(null)
// a thread is a top-level comment // a thread comment is a comment at depth 1 (parent)
const thread = item.path?.split('.').length === 2 const thread = depth === 1
// recurse through all new comments and their children // recurse through all new comments and their children
// if the item is a thread, we also consider all of their existing children // if the item is a thread, we also consider all of their existing children

View File

@ -7,12 +7,13 @@ import { itemUpdateQuery, commentUpdateFragment, getLatestCommentCreatedAt } fro
const POLL_INTERVAL = 1000 * 10 // 10 seconds const POLL_INTERVAL = 1000 * 10 // 10 seconds
// merge new comment into item's newComments // merge new comment into item's newComments
// and prevent duplicates by checking if the comment is already in item's newComments // and prevent duplicates by checking if the comment is already in item's newComments or existing comments
function mergeNewComment (item, newComment) { function mergeNewComment (item, newComment) {
const existingNewComments = item.newComments || [] const existingNewComments = item.newComments || []
const existingComments = item.comments?.comments || []
// is the incoming new comment already in item's new comments? // is the incoming new comment already in item's new comments or existing comments?
if (existingNewComments.includes(newComment.id)) { if (existingNewComments.includes(newComment.id) || existingComments.some(comment => comment.id === newComment.id)) {
return item return item
} }