inform user when there are new comments
This commit is contained in:
parent
0f5fc31803
commit
297270f34d
|
@ -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
|
||||
</Nav.Link>
|
||||
</Link>
|
||||
{sub !== 'jobs' && (!me || me.noteJobIndicator) && (!lastCheckedJobs || lastCheckedJobs < subLatestPost?.subLatestPost) &&
|
||||
{showJobIndicator &&
|
||||
<span className={styles.jobIndicator}>
|
||||
<span className='invisible'>{' '}</span>
|
||||
</span>}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }) {
|
|||
<span> \ </span>
|
||||
</>}
|
||||
<Link href={`/items/${item.id}`} passHref>
|
||||
<a title={`${item.commentSats} sats`} className='text-reset'>{item.ncomments} comments</a>
|
||||
<a title={`${item.commentSats} sats`} className='text-reset'>
|
||||
{item.ncomments} comments
|
||||
{hasNewComments && <>{' '}<Badge className={styles.newComment} variant={null}>new</Badge></>}
|
||||
</a>
|
||||
</Link>
|
||||
<span> \ </span>
|
||||
<span>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue