Skip to content

Commit d15a024

Browse files
committed
fix: read new comments fragments to inject fresh new comments, fixing dropped comments;
ui: show amount of new comments refactor: correct function positioning; cleanup: useless logs
1 parent e797011 commit d15a024

File tree

1 file changed

+37
-36
lines changed

1 file changed

+37
-36
lines changed

components/use-live-comments.js

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,6 @@ import styles from './comment.module.css'
77

88
const POLL_INTERVAL = 1000 * 10 // 10 seconds
99

10-
// the item query is used to update the item's newComments field
11-
function itemUpdateQuery (client, id, sort, fn) {
12-
client.cache.updateQuery({
13-
query: ITEM_FULL,
14-
variables: sort === 'top' ? { id } : { id, sort }
15-
}, (data) => {
16-
if (!data) return data
17-
return { item: fn(data.item) }
18-
})
19-
}
20-
21-
function commentUpdateFragment (client, id, fn) {
22-
client.cache.updateFragment({
23-
id: `Item:${id}`,
24-
fragment: COMMENT_WITH_NEW,
25-
fragmentName: 'CommentWithNew'
26-
}, (data) => {
27-
if (!data) return data
28-
return { ...data, ...fn(data) }
29-
})
30-
}
31-
32-
function dedupeComments (existing = [], incoming = []) {
33-
const existingIds = new Set(existing.map(c => c.id))
34-
return [...incoming.filter(c => !existingIds.has(c.id)), ...existing]
35-
}
36-
3710
export default function useLiveComments (rootId, after, sort) {
3811
const client = useApolloClient()
3912
const [latest, setLatest] = useState(after)
@@ -62,17 +35,37 @@ export default function useLiveComments (rootId, after, sort) {
6235
}, [data, client, rootId, sort])
6336
}
6437

38+
// the item query is used to update the item's newComments field
39+
function itemUpdateQuery (client, id, sort, fn) {
40+
client.cache.updateQuery({
41+
query: ITEM_FULL,
42+
variables: sort === 'top' ? { id } : { id, sort }
43+
}, (data) => {
44+
if (!data) return data
45+
return { item: fn(data.item) }
46+
})
47+
}
48+
49+
function commentUpdateFragment (client, id, fn) {
50+
client.cache.updateFragment({
51+
id: `Item:${id}`,
52+
fragment: COMMENT_WITH_NEW,
53+
fragmentName: 'CommentWithNew'
54+
}, (data) => {
55+
if (!data) return data
56+
return fn(data)
57+
})
58+
}
59+
6560
function cacheNewComments (client, rootId, newComments, sort) {
6661
const queuedComments = []
6762

6863
for (const newComment of newComments) {
69-
console.log('newComment', newComment)
7064
const { parentId } = newComment
7165
const topLevel = Number(parentId) === Number(rootId)
7266

7367
// if the comment is a top level comment, update the item
7468
if (topLevel) {
75-
console.log('topLevel', topLevel)
7669
itemUpdateQuery(client, rootId, sort, (data) => mergeNewComment(data, newComment))
7770
} else {
7871
// check if parent exists in cache before attempting update
@@ -84,7 +77,6 @@ function cacheNewComments (client, rootId, newComments, sort) {
8477

8578
if (parentExists) {
8679
// if the comment is a reply, update the parent comment
87-
console.log('reply', parentId)
8880
commentUpdateFragment(client, parentId, (data) => mergeNewComment(data, newComment))
8981
} else {
9082
// parent not in cache, queue for retry
@@ -99,17 +91,23 @@ function cacheNewComments (client, rootId, newComments, sort) {
9991
// merge new comment into item's newComments
10092
// if the new comment is already in item's newComments or existing comments, do nothing
10193
function mergeNewComment (item, newComment) {
102-
console.log('mergeNewComment', item, newComment)
10394
const existingNewComments = item.newComments || []
10495
const existingComments = item.comments?.comments || []
10596

10697
// is the incoming new comment already in item's new comments or existing comments?
10798
if (existingNewComments.some(c => c.id === newComment.id) || existingComments.some(c => c.id === newComment.id)) {
10899
return item
109100
}
101+
110102
return { ...item, newComments: [...existingNewComments, newComment] }
111103
}
112104

105+
// dedupe comments by id
106+
function dedupeComments (existing = [], incoming = []) {
107+
const existingIds = new Set(existing.map(c => c.id))
108+
return [...incoming.filter(c => !existingIds.has(c.id)), ...existing]
109+
}
110+
113111
function getLatestCommentCreatedAt (comments, latest) {
114112
if (comments.length === 0) return latest
115113

@@ -127,19 +125,22 @@ export function ShowNewComments ({ newComments = [], itemId, topLevel = false, s
127125

128126
const showNewComments = useCallback(() => {
129127
const payload = (data) => {
130-
if (!data) return data
128+
// fresh newComments
129+
const freshNewComments = newComments.map(c => client.cache.readFragment({
130+
id: `Item:${c.id}`,
131+
fragment: COMMENT_WITH_NEW,
132+
fragmentName: 'CommentWithNew'
133+
}))
131134
return {
132135
...data,
133-
comments: { ...data.comments, comments: dedupeComments(data.comments.comments, newComments) },
136+
comments: { ...data.comments, comments: dedupeComments(data.comments.comments, freshNewComments) },
134137
newComments: []
135138
}
136139
}
137140

138141
if (topLevel) {
139-
console.log('topLevel', topLevel)
140142
itemUpdateQuery(client, itemId, sort, payload)
141143
} else {
142-
console.log('reply', itemId)
143144
commentUpdateFragment(client, itemId, payload)
144145
}
145146
}, [client, itemId, newComments, topLevel, sort])
@@ -149,7 +150,7 @@ export function ShowNewComments ({ newComments = [], itemId, topLevel = false, s
149150
onClick={showNewComments}
150151
className={`${topLevel && `d-block fw-bold ${styles.comment} pb-2`} d-flex align-items-center gap-2 px-3 pointer`}
151152
>
152-
load new comments
153+
show ({newComments.length}) new comments
153154
<div className={styles.newCommentDot} />
154155
</div>
155156
)

0 commit comments

Comments
 (0)