soxa b5af28c48b
Server-side tracking of comments view time (#2432)
* server-side comments view tracking, model structure, mutation

* full commentsViewedAt refactor, adjust comment creation and injection, adjust item navigation

* update server-side tracking only if there's a change, light cleanup

* coalesce meCommentsViewedAt to the item's createdAt, wip PoC comment outlining

* don't update cache on item visit, use useRoot hook for outlining

* add meCommentsViewedAt to root, better naming, light cleanup

* better timestamp logic and comparisons, add lastCommentAt to root item object, added TODOs

* fix: track commentsViewedAt only for root item, use topLevelId to fetch live comments only for the current item

* only track commentsViewedAt for root item, light cleanup

* light cleanup, correct live comments timestamp deps

* worker: on midnight, untrack items that were never viewed and had no comments in the last 21 days
2025-09-02 13:13:44 -05:00

224 lines
3.6 KiB
JavaScript

import { gql } from '@apollo/client'
import { COMMENTS } from './comments'
// we can't import from users because of circular dependency
const STREAK_FIELDS = gql`
fragment StreakFields on User {
optional {
streak
hasSendWallet
hasRecvWallet
}
}
`
export const ITEM_FIELDS = gql`
${STREAK_FIELDS}
fragment ItemFields on Item {
id
parentId
createdAt
invoicePaidAt
deletedAt
title
url
user {
id
name
meMute
...StreakFields
}
sub {
name
userId
moderated
meMuteSub
meSubscription
nsfw
replyCost
}
otsHash
position
sats
credits
meAnonSats @client
boost
bounty
bountyPaidTo
noteId
path
upvotes
meSats
meCredits
meDontLikeSats
meBookmark
meSubscription
meForward
outlawed
freebie
bio
ncomments
nDirectComments
commentSats
commentCredits
lastCommentAt
isJob
status
company
location
remote
subName
pollCost
pollExpiresAt
uploadId
mine
imgproxyUrls
rel
apiKey
invoice {
id
actionState
confirmedAt
}
cost
meCommentsViewedAt
}`
export const ITEM_FULL_FIELDS = gql`
${ITEM_FIELDS}
${STREAK_FIELDS}
fragment ItemFullFields on Item {
...ItemFields
text
root {
id
createdAt
title
bounty
bountyPaidTo
subName
mine
ncomments
lastCommentAt
meCommentsViewedAt
user {
id
name
...StreakFields
}
sub {
name
userId
moderated
meMuteSub
meSubscription
replyCost
}
}
forwards {
userId
pct
user {
name
}
}
}`
export const ITEM_OTS_FIELDS = gql`
fragment ItemOtsFields on Item {
id
title
text
url
parentOtsHash
otsHash
deletedAt
}`
export const ITEM_OTS = gql`
${ITEM_OTS_FIELDS}
query Item($id: ID!) {
item(id: $id) {
...ItemOtsFields
}
}`
export const POLL_FIELDS = gql`
fragment PollFields on Item {
poll {
meVoted
meInvoiceId
meInvoiceActionState
count
options {
id
option
count
}
randPollOptions
}
}`
export const ITEM = gql`
${ITEM_FULL_FIELDS}
${POLL_FIELDS}
query Item($id: ID!) {
item(id: $id) {
...ItemFullFields
...PollFields
}
}`
export const ITEM_FULL = gql`
${ITEM_FULL_FIELDS}
${POLL_FIELDS}
${COMMENTS}
query Item($id: ID!, $sort: String, $cursor: String) {
item(id: $id) {
...ItemFullFields
prior
...PollFields
comments(sort: $sort, cursor: $cursor) {
cursor
comments {
...CommentsRecursive
}
}
}
}`
export const RELATED_ITEMS = gql`
${ITEM_FIELDS}
query Related($title: String, $id: ID, $cursor: String, $limit: Limit) {
related(title: $title, id: $id, cursor: $cursor, limit: $limit) {
cursor
items {
...ItemFields
}
}
}
`
export const RELATED_ITEMS_WITH_ITEM = gql`
${ITEM_FIELDS}
query Related($title: String, $id: ID!, $cursor: String, $limit: Limit) {
item(id: $id) {
...ItemFields
}
related(title: $title, id: $id, cursor: $cursor, limit: $limit) {
cursor
items {
...ItemFields
}
}
}
`
export const UPDATE_ITEM_USER_VIEW = gql`
mutation updateCommentsViewAt($id: ID!, $meCommentsViewedAt: Date!) {
updateCommentsViewAt(id: $id, meCommentsViewedAt: $meCommentsViewedAt)
}
`