@@ -3,7 +3,11 @@ import { SSR } from '../lib/constants'
3
3
import { GET_NEW_COMMENTS , COMMENT_WITH_NEW } from '../fragments/comments'
4
4
import { ITEM_FULL } from '../fragments/items'
5
5
import { useEffect , useState } from 'react'
6
- import styles from './comments.module.css'
6
+ import styles from './comment.module.css'
7
+
8
+ const POLL_INTERVAL = 1000 * 10 // 10 seconds
9
+ const ACTIVITY_TIMEOUT = 1000 * 60 * 30 // 30 minutes
10
+ const ACTIVITY_CHECK_INTERVAL = 1000 * 60 // 1 minute
7
11
8
12
export default function useLiveComments ( rootId , after ) {
9
13
const client = useApolloClient ( )
@@ -25,19 +29,20 @@ export default function useLiveComments (rootId, after) {
25
29
const isActive = document . visibilityState === 'visible'
26
30
27
31
// poll only if the user is active and has been active in the last 30 minutes
28
- if ( timeSinceEngaged < 1000 * 60 * 30 ) {
32
+ if ( timeSinceEngaged < ACTIVITY_TIMEOUT ) {
29
33
setPolling ( isActive )
30
34
} else {
31
35
setPolling ( false )
32
36
}
33
37
}
34
38
35
39
// check activity every minute
36
- const interval = setInterval ( checkActivity , 1000 * 60 )
40
+ const interval = setInterval ( checkActivity , ACTIVITY_CHECK_INTERVAL )
37
41
// check activity also on visibility change
38
42
document . addEventListener ( 'visibilitychange' , checkActivity )
39
43
40
44
return ( ) => {
45
+ // cleanup
41
46
document . removeEventListener ( 'visibilitychange' , checkActivity )
42
47
clearInterval ( interval )
43
48
}
@@ -46,25 +51,22 @@ export default function useLiveComments (rootId, after) {
46
51
const { data } = useQuery ( GET_NEW_COMMENTS , SSR
47
52
? { }
48
53
: {
49
- pollInterval : polling ? 10000 : null ,
54
+ pollInterval : polling ? POLL_INTERVAL : null ,
50
55
variables : { rootId, after : latest }
51
56
} )
52
57
53
58
useEffect ( ( ) => {
54
- if ( data && data . newComments ) {
55
- saveNewComments ( client , rootId , data . newComments . comments )
56
- // check new comments created after the latest new comment
57
- const latestCommentCreatedAt = getLatestCommentCreatedAt ( data . newComments . comments , latest )
58
- if ( latestCommentCreatedAt ) {
59
- setLatest ( latestCommentCreatedAt )
60
- }
61
- }
62
- } , [ data , client , rootId , latest ] )
59
+ if ( ! data ?. newComments ) return
60
+
61
+ cacheNewComments ( client , rootId , data . newComments . comments )
62
+ // check new comments created after the latest new comment
63
+ setLatest ( prevLatest => getLatestCommentCreatedAt ( data . newComments . comments , prevLatest ) )
64
+ } , [ data , client , rootId ] )
63
65
64
66
return { polling, setPolling }
65
67
}
66
68
67
- function saveNewComments ( client , rootId , newComments ) {
69
+ function cacheNewComments ( client , rootId , newComments ) {
68
70
for ( const newComment of newComments ) {
69
71
const { parentId } = newComment
70
72
const topLevel = Number ( parentId ) === Number ( rootId )
@@ -77,7 +79,7 @@ function saveNewComments (client, rootId, newComments) {
77
79
} , ( data ) => {
78
80
if ( ! data ) return data
79
81
// we return the entire item, not just the newComments
80
- return { item : dedupeComment ( data ?. item , newComment ) }
82
+ return { item : mergeNewComments ( data ?. item , newComment ) }
81
83
} )
82
84
} else {
83
85
// if the comment is a reply, update the parent comment
@@ -88,13 +90,13 @@ function saveNewComments (client, rootId, newComments) {
88
90
} , ( data ) => {
89
91
if ( ! data ) return data
90
92
// here we return the parent comment with the new comment added
91
- return dedupeComment ( data , newComment )
93
+ return mergeNewComments ( data , newComment )
92
94
} )
93
95
}
94
96
}
95
97
}
96
98
97
- function dedupeComment ( item , newComment ) {
99
+ function mergeNewComments ( item , newComment ) {
98
100
const existingNewComments = item . newComments || [ ]
99
101
const existingComments = item . comments ?. comments || [ ]
100
102
@@ -106,15 +108,15 @@ function dedupeComment (item, newComment) {
106
108
}
107
109
108
110
function getLatestCommentCreatedAt ( comments , latest ) {
109
- if ( comments . length === 0 ) return null
110
-
111
- for ( const comment of comments ) {
112
- if ( comment . createdAt > latest ) {
113
- latest = comment . createdAt
114
- }
115
- }
116
-
117
- return latest
111
+ if ( comments . length === 0 ) return latest
112
+
113
+ // timestamp comparison via Math.max on bare timestamps
114
+ // convert all createdAt to timestamps
115
+ const timestamps = comments . map ( c => new Date ( c . createdAt ) . getTime ( ) )
116
+ // find the latest timestamp
117
+ const maxTimestamp = Math . max ( ... timestamps , new Date ( latest ) . getTime ( ) )
118
+ // convert back to ISO string
119
+ return new Date ( maxTimestamp ) . toISOString ( )
118
120
}
119
121
120
122
export function ShowNewComments ( { newComments = [ ] , itemId, topLevel = false } ) {
0 commit comments