* Fix duplicate comment on pessimistic creation - comment creation checks for comment's ID existence in cache - invoice.confirmedAt included in useCanEdit deps for anons live comments * switch to some as sets are not worth it * only check for duplicates if a pessimistic payment method has been used * default to empty array * add comment about side-effects * record ownership of an item to avoid injecting it via live comments * trigger check only if the incoming comment is ours, cleanup * correct conditions, correct comments, light cleanup * fix: add defensive condition to ownership recorder, better name * refactor: unified comment injection logic with deduplication, useCommentsView hook; revert sessionStorage-based fix * adjust live comments naming around the codebase * listen for hmac presence for anon edits * always return the injected comment createdAt to bump live comments * refactor: improve live comments hook readability - latest comment createdAt persistence helper - preserveScroll returns the returning value of the callback - compact conditional logic - refresh code comments - refresh naming - group constants - reorder imports * flat comment injection, fetch flat comments instead of the entire subtree that would've been deduplicated anyway, cleanup * always align new comment fragment to the comments query structure * generic useCommentsView hook * update comment counts if live injecting into fragments without comments field * fix: pass parentId, if a comment has a top level parent it always has the comments field * fix: update CommentsViewAt only if we actually injected a comment into cache * correct injectComment result usage * pass markViewedAt to further centralize side effects, remove live from Item server typedefs * fix: don't update counts for ancestors that are already up to date, update commentsViewedAt per batch not per comment * port: fix coalesce, useCommentsView hook and outline changes * update hmac field in cache on paid invoice, hmac as useCanEdit effect dependency * comments and light cleanup, update useCommentsView * efficient hasComments logic for live comments, establish a gql fragment * fix: typo on topLevel evaluation * limit extra evaluations to live comments scenarios * update comments * support live comments ncomments increments for anon view tracking
88 lines
2.8 KiB
JavaScript
88 lines
2.8 KiB
JavaScript
import { COMMENTS, HAS_COMMENTS } from '../fragments/comments'
|
|
|
|
// adds a comment to the cache, under its parent item
|
|
function cacheComment (cache, newComment, { live = false }) {
|
|
return cache.modify({
|
|
id: `Item:${newComment.parentId}`,
|
|
fields: {
|
|
comments: (existingComments = {}, { readField }) => {
|
|
// if the comment already exists, return
|
|
if (existingComments?.comments?.some(c => readField('id', c) === newComment.id)) return existingComments
|
|
|
|
// we need to make sure we're writing a fragment that matches the comments query (comments and count fields)
|
|
const newCommentRef = cache.writeFragment({
|
|
data: {
|
|
comments: {
|
|
comments: []
|
|
},
|
|
ncomments: 0,
|
|
nDirectComments: 0,
|
|
...newComment,
|
|
live
|
|
},
|
|
fragment: COMMENTS,
|
|
fragmentName: 'CommentsRecursive'
|
|
})
|
|
|
|
return {
|
|
cursor: existingComments.cursor,
|
|
comments: [newCommentRef, ...(existingComments?.comments || [])]
|
|
}
|
|
}
|
|
},
|
|
optimistic: true
|
|
})
|
|
}
|
|
|
|
// handles cache injection and side-effects for both live and non-live comments
|
|
export function injectComment (cache, newComment, { live = false, rootId } = {}) {
|
|
// if live and a reply (not top level), check if the parent has comments
|
|
const hasComments = live && !(Number(rootId) === Number(newComment.parentId))
|
|
? !!(cache.readFragment({
|
|
id: `Item:${newComment.parentId}`,
|
|
fragment: HAS_COMMENTS
|
|
}))
|
|
// if not live, we can assume the parent has the comments field since user replied to it
|
|
: true
|
|
|
|
const updated = hasComments && cacheComment(cache, newComment, { live })
|
|
|
|
// run side effects if injection succeeded or if injecting live comment into SSR item without comments field
|
|
if (updated || (live && !hasComments)) {
|
|
// update all ancestors comment count, excluding the comment itself
|
|
const ancestors = newComment.path.split('.').slice(0, -1)
|
|
updateAncestorsCommentCount(cache, ancestors)
|
|
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// updates the ncomments and nDirectComments fields of all ancestors of an item/comment in the cache
|
|
function updateAncestorsCommentCount (cache, ancestors, { ncomments = 1, nDirectComments = 1 } = {}) {
|
|
// update nDirectComments of immediate parent
|
|
cache.modify({
|
|
id: `Item:${ancestors[ancestors.length - 1]}`,
|
|
fields: {
|
|
nDirectComments (existingNDirectComments = 0) {
|
|
return existingNDirectComments + nDirectComments
|
|
}
|
|
},
|
|
optimistic: true
|
|
})
|
|
|
|
// update ncomments of all ancestors
|
|
ancestors.forEach(id => {
|
|
cache.modify({
|
|
id: `Item:${id}`,
|
|
fields: {
|
|
ncomments (existingNComments = 0) {
|
|
return existingNComments + ncomments
|
|
}
|
|
},
|
|
optimistic: true
|
|
})
|
|
})
|
|
}
|