diff --git a/components/header.js b/components/header.js
index 66593564..30316f75 100644
--- a/components/header.js
+++ b/components/header.js
@@ -129,6 +129,9 @@ export default function Header ({ sub }) {
}
}
+ const showJobIndicator = sub !== 'jobs' && (!me || me.noteJobIndicator) &&
+ (!lastCheckedJobs || lastCheckedJobs < subLatestPost?.subLatestPost)
+
const NavItems = ({ className }) => {
return (
<>
@@ -150,7 +153,7 @@ export default function Header ({ sub }) {
jobs
- {sub !== 'jobs' && (!me || me.noteJobIndicator) && (!lastCheckedJobs || lastCheckedJobs < subLatestPost?.subLatestPost) &&
+ {showJobIndicator &&
{' '}
}
diff --git a/components/item-full.js b/components/item-full.js
index 562d9e1a..60f6c1f2 100644
--- a/components/item-full.js
+++ b/components/item-full.js
@@ -11,8 +11,9 @@ import { Button } from 'react-bootstrap'
import { TwitterTweetEmbed } from 'react-twitter-embed'
import YouTube from 'react-youtube'
import useDarkMode from 'use-dark-mode'
-import { useState } from 'react'
+import { useEffect, useState } from 'react'
import Poll from './poll'
+import { commentsViewed } from '../lib/new-comments'
function BioItem ({ item, handleClick }) {
const me = useMe()
@@ -99,6 +100,10 @@ function ItemText ({ item }) {
}
export default function ItemFull ({ item, bio, ...props }) {
+ useEffect(() => {
+ commentsViewed(item)
+ }, [item.lastCommentAt])
+
return (
<>
{item.parentId
diff --git a/components/item.js b/components/item.js
index a4b7c31c..f41559c2 100644
--- a/components/item.js
+++ b/components/item.js
@@ -9,6 +9,8 @@ import Pin from '../svgs/pushpin-fill.svg'
import reactStringReplace from 'react-string-replace'
import Toc from './table-of-contents'
import PollIcon from '../svgs/bar-chart-horizontal-fill.svg'
+import { Badge } from 'react-bootstrap'
+import { newComments } from '../lib/new-comments'
export function SearchTitle ({ title }) {
return reactStringReplace(title, /:high\[([^\]]+)\]/g, (match, i) => {
@@ -34,6 +36,7 @@ export default function Item ({ item, rank, showFwdUser, toc, children }) {
useState(mine && (Date.now() < editThreshold))
const [wrap, setWrap] = useState(false)
const titleRef = useRef()
+ const [hasNewComments, setHasNewComments] = useState(false)
useEffect(() => {
setWrap(
@@ -41,6 +44,11 @@ export default function Item ({ item, rank, showFwdUser, toc, children }) {
titleRef.current.clientHeight)
}, [])
+ useEffect(() => {
+ // if we are showing toc, then this is a full item
+ setHasNewComments(!toc && newComments(item))
+ }, [item])
+
return (
<>
{rank
@@ -82,7 +90,10 @@ export default function Item ({ item, rank, showFwdUser, toc, children }) {
\
>}
- {item.ncomments} comments
+
+ {item.ncomments} comments
+ {hasNewComments && <>{' '}new>}
+
\
diff --git a/components/item.module.css b/components/item.module.css
index 75fe64ab..41b8515d 100644
--- a/components/item.module.css
+++ b/components/item.module.css
@@ -20,6 +20,11 @@ a.title:visited {
flex: 1 0 128px;
}
+.newComment {
+ color: var(--theme-grey) !important;
+ background: var(--theme-clickToContextColor) !important;
+}
+
.pin {
fill: #a5a5a5;
margin-right: .2rem;
diff --git a/components/reply.js b/components/reply.js
index 4239e698..44fade81 100644
--- a/components/reply.js
+++ b/components/reply.js
@@ -8,6 +8,7 @@ import TextareaAutosize from 'react-textarea-autosize'
import { useEffect, useState } from 'react'
import Link from 'next/link'
import FeeButton from './fee-button'
+import { commentsViewedAfterComment } from '../lib/new-comments'
export const CommentSchema = Yup.object({
text: Yup.string().required('required').trim()
@@ -57,8 +58,10 @@ export default function Reply ({ item, onSuccess, replyOpen }) {
}
})
+ const ancestors = item.path.split('.')
+
// update all ancestors
- item.path.split('.').forEach(id => {
+ ancestors.forEach(id => {
cache.modify({
id: `Item:${id}`,
fields: {
@@ -68,6 +71,11 @@ export default function Reply ({ item, onSuccess, replyOpen }) {
}
})
})
+
+ // so that we don't see indicator for our own comments, we record this comments as the latest time
+ // but we also have record num comments, in case someone else commented when we did
+ const root = ancestors[0]
+ commentsViewedAfterComment(root, createComment.createdAt)
}
}
)
diff --git a/lib/new-comments.js b/lib/new-comments.js
new file mode 100644
index 00000000..9e63ad86
--- /dev/null
+++ b/lib/new-comments.js
@@ -0,0 +1,28 @@
+const COMMENTS_VIEW_PREFIX = 'commentsViewedAt'
+const COMMENTS_NUM_PREFIX = 'commentsViewNum'
+
+export function commentsViewed (item) {
+ if (!item.parentId && item.lastCommentAt) {
+ localStorage.setItem(`${COMMENTS_VIEW_PREFIX}:${item.id}`, new Date(item.lastCommentAt).getTime())
+ localStorage.setItem(`${COMMENTS_NUM_PREFIX}:${item.id}`, item.ncomments)
+ }
+}
+
+export function commentsViewedAfterComment (rootId, createdAt) {
+ localStorage.setItem(`${COMMENTS_VIEW_PREFIX}:${rootId}`, new Date(createdAt).getTime())
+ const existingRootComments = localStorage.getItem(`${COMMENTS_NUM_PREFIX}:${rootId}`) || 0
+ localStorage.setItem(`${COMMENTS_NUM_PREFIX}:${rootId}`, existingRootComments + 1)
+}
+
+export function newComments (item) {
+ if (!item.parentId) {
+ const commentsViewedAt = localStorage.getItem(`${COMMENTS_VIEW_PREFIX}:${item.id}`)
+ const commentsViewNum = localStorage.getItem(`${COMMENTS_NUM_PREFIX}:${item.id}`)
+
+ if (commentsViewedAt && commentsViewNum) {
+ return commentsViewedAt < new Date(item.lastCommentAt).getTime() || commentsViewNum < item.ncomments
+ }
+ }
+
+ return false
+}