continued notification work
This commit is contained in:
parent
c8df41bfa5
commit
0afe46c030
@ -5,9 +5,9 @@ export default {
|
|||||||
Query: {
|
Query: {
|
||||||
notifications: async (parent, { cursor }, { me, models }) => {
|
notifications: async (parent, { cursor }, { me, models }) => {
|
||||||
const decodedCursor = decodeCursor(cursor)
|
const decodedCursor = decodeCursor(cursor)
|
||||||
// if (!me) {
|
if (!me) {
|
||||||
// throw new AuthenticationError('you must be logged in')
|
throw new AuthenticationError('you must be logged in')
|
||||||
// }
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
So that we can cursor over results, we union notifications together ...
|
So that we can cursor over results, we union notifications together ...
|
||||||
@ -63,12 +63,15 @@ export default {
|
|||||||
GROUP BY ${ITEM_SUBQUERY_FIELDS}, subquery.island ORDER BY max(subquery.voted_at) desc)
|
GROUP BY ${ITEM_SUBQUERY_FIELDS}, subquery.island ORDER BY max(subquery.voted_at) desc)
|
||||||
ORDER BY sort_time DESC
|
ORDER BY sort_time DESC
|
||||||
OFFSET $3
|
OFFSET $3
|
||||||
LIMIT ${LIMIT}`, 622, decodedCursor.time, decodedCursor.offset)
|
LIMIT ${LIMIT}`, me.id, decodedCursor.time, decodedCursor.offset)
|
||||||
|
|
||||||
notifications = notifications.map(n => {
|
notifications = notifications.map(n => {
|
||||||
n.item = { ...n }
|
n.item = { ...n }
|
||||||
return n
|
return n
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await models.user.update({ where: { id: me.id }, data: { checkedNotesAt: new Date() } })
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cursor: notifications.length === LIMIT ? nextCursorEncoded(decodedCursor) : null,
|
cursor: notifications.length === LIMIT ? nextCursorEncoded(decodedCursor) : null,
|
||||||
notifications
|
notifications
|
||||||
|
@ -38,7 +38,7 @@ function Parent ({ item, rootText }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Comment ({ item, children, replyOpen, includeParent, rootText, noComments, noReply, clickToContext }) {
|
export default function Comment ({ item, children, replyOpen, includeParent, rootText, noComments, noReply }) {
|
||||||
const [reply, setReply] = useState(replyOpen)
|
const [reply, setReply] = useState(replyOpen)
|
||||||
const [edit, setEdit] = useState()
|
const [edit, setEdit] = useState()
|
||||||
const [collapse, setCollapse] = useState(false)
|
const [collapse, setCollapse] = useState(false)
|
||||||
@ -50,28 +50,16 @@ export default function Comment ({ item, children, replyOpen, includeParent, roo
|
|||||||
const [canEdit, setCanEdit] =
|
const [canEdit, setCanEdit] =
|
||||||
useState(mine && (Date.now() < editThreshold))
|
useState(mine && (Date.now() < editThreshold))
|
||||||
|
|
||||||
console.log('wtf router', router, item.id, ref.current)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (Number(router.query.commentId) === Number(item.id)) {
|
if (Number(router.query.commentId) === Number(item.id)) {
|
||||||
console.log(ref.current.scrollTop)
|
|
||||||
ref.current.scrollIntoView()
|
ref.current.scrollIntoView()
|
||||||
// ref.current.classList.add('flash-it')
|
ref.current.classList.add('flash-it')
|
||||||
}
|
}
|
||||||
}, [item])
|
}, [item])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ref} onClick={() => {
|
ref={ref} className={includeParent ? '' : `${styles.comment} ${collapse ? styles.collapsed : ''}`}
|
||||||
if (clickToContext) {
|
|
||||||
console.log('pushing')
|
|
||||||
// router.push(`/items/${item.parentId}?commentId=${item.id}`, `/items/${item.parentId}`, { scroll: false })
|
|
||||||
router.push({
|
|
||||||
pathname: '/items/[id]',
|
|
||||||
query: { id: item.parentId, commentId: item.id }
|
|
||||||
}, `/items/${item.parentId}`)
|
|
||||||
}
|
|
||||||
}} className={includeParent ? `${clickToContext ? styles.clickToContext : ''}` : `${styles.comment} ${collapse ? styles.collapsed : ''}`}
|
|
||||||
>
|
>
|
||||||
<div className={`${itemStyles.item} ${styles.item}`}>
|
<div className={`${itemStyles.item} ${styles.item}`}>
|
||||||
<UpVote itemId={item.id} meSats={item.meSats} className={styles.upvote} />
|
<UpVote itemId={item.id} meSats={item.meSats} className={styles.upvote} />
|
||||||
|
@ -81,15 +81,6 @@
|
|||||||
padding-left: .2rem;
|
padding-left: .2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.clickToContext {
|
|
||||||
border-radius: .4rem;
|
|
||||||
padding: .2rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clickToContext:hover {
|
|
||||||
background-color: rgba(0, 0, 0, 0.03);
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment:not(:last-child) {
|
.comment:not(:last-child) {
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
@ -100,8 +91,3 @@
|
|||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.clickToContext {
|
|
||||||
scroll-behavior: smooth;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
@ -3,8 +3,11 @@ import Button from 'react-bootstrap/Button'
|
|||||||
import { MORE_FLAT_COMMENTS } from '../fragments/comments'
|
import { MORE_FLAT_COMMENTS } from '../fragments/comments'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import Comment, { CommentSkeleton } from './comment'
|
import Comment, { CommentSkeleton } from './comment'
|
||||||
|
import styles from './notifications.module.css'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
export default function CommentsFlat ({ variables, ...props }) {
|
export default function CommentsFlat ({ variables, ...props }) {
|
||||||
|
const router = useRouter()
|
||||||
const { loading, error, data, fetchMore } = useQuery(MORE_FLAT_COMMENTS, {
|
const { loading, error, data, fetchMore } = useQuery(MORE_FLAT_COMMENTS, {
|
||||||
variables
|
variables
|
||||||
})
|
})
|
||||||
@ -12,12 +15,22 @@ export default function CommentsFlat ({ variables, ...props }) {
|
|||||||
if (loading) {
|
if (loading) {
|
||||||
return <CommentsFlatSkeleton />
|
return <CommentsFlatSkeleton />
|
||||||
}
|
}
|
||||||
|
|
||||||
const { moreFlatComments: { comments, cursor } } = data
|
const { moreFlatComments: { comments, cursor } } = data
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{comments.map(item => (
|
{comments.map(item => (
|
||||||
<Comment key={item.id} item={item} {...props} />
|
<div
|
||||||
|
key={item.id}
|
||||||
|
className={styles.clickToContext}
|
||||||
|
onClick={() => {
|
||||||
|
router.push({
|
||||||
|
pathname: '/items/[id]',
|
||||||
|
query: { id: item.parentId, commentId: item.id }
|
||||||
|
}, `/items/${item.parentId}`)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Comment item={item} {...props} />
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
<MoreFooter cursor={cursor} fetchMore={fetchMore} />
|
<MoreFooter cursor={cursor} fetchMore={fetchMore} />
|
||||||
</>
|
</>
|
||||||
|
@ -14,7 +14,7 @@ import { useEffect } from 'react'
|
|||||||
import { randInRange } from '../lib/rand'
|
import { randInRange } from '../lib/rand'
|
||||||
|
|
||||||
function WalletSummary ({ me }) {
|
function WalletSummary ({ me }) {
|
||||||
return `[${me.stacked},${me.sats}]`
|
return `${me.stacked} \\ ${me.sats}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Header () {
|
export default function Header () {
|
||||||
@ -32,20 +32,18 @@ export default function Header () {
|
|||||||
if (session) {
|
if (session) {
|
||||||
return (
|
return (
|
||||||
<div className='d-flex align-items-center'>
|
<div className='d-flex align-items-center'>
|
||||||
{me && me.hasNewNotes &&
|
|
||||||
<Head>
|
<Head>
|
||||||
<link rel='shortcut icon' href='/favicon-notify.png' />
|
<link rel='shortcut icon' href={me && me.hasNewNotes ? '/favicon-notify.png' : '/favicon.png'} />
|
||||||
</Head>}
|
</Head>
|
||||||
<div className='position-relative'>
|
<div className='position-relative'>
|
||||||
<NavDropdown className='pl-0' title={`@${session.user.name}`} alignRight>
|
<NavDropdown className='px-0' title={`@${session.user.name}`} alignRight>
|
||||||
<Link href={'/' + session.user.name} passHref>
|
<Link href={'/' + session.user.name} passHref>
|
||||||
<NavDropdown.Item>profile</NavDropdown.Item>
|
<NavDropdown.Item>profile</NavDropdown.Item>
|
||||||
</Link>
|
</Link>
|
||||||
<Link href='/notifications' passHref>
|
<Link href='/notifications' passHref>
|
||||||
<NavDropdown.Item onClick={() => {
|
<NavDropdown.Item onClick={() => {
|
||||||
// when it's a fresh click evict old notification cache
|
// when it's a fresh click evict old notification cache
|
||||||
client.cache.evict({ id: 'ROOT_QUERY', fieldName: 'moreFlatComments:{}' })
|
client.cache.evict({ id: 'ROOT_QUERY', fieldName: 'notifications' })
|
||||||
client.cache.evict({ id: 'ROOT_QUERY', fieldName: 'recentlyStacked' })
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
notifications
|
notifications
|
||||||
|
@ -4,8 +4,11 @@ import { useState } from 'react'
|
|||||||
import Comment, { CommentSkeleton } from './comment'
|
import Comment, { CommentSkeleton } from './comment'
|
||||||
import Item from './item'
|
import Item from './item'
|
||||||
import { NOTIFICATIONS } from '../fragments/notifications'
|
import { NOTIFICATIONS } from '../fragments/notifications'
|
||||||
|
import styles from './notifications.module.css'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
export default function Notifications ({ variables, ...props }) {
|
export default function Notifications ({ variables, ...props }) {
|
||||||
|
const router = useRouter()
|
||||||
const { loading, error, data, fetchMore } = useQuery(NOTIFICATIONS, {
|
const { loading, error, data, fetchMore } = useQuery(NOTIFICATIONS, {
|
||||||
variables
|
variables
|
||||||
})
|
})
|
||||||
@ -14,12 +17,26 @@ export default function Notifications ({ variables, ...props }) {
|
|||||||
return <CommentsFlatSkeleton />
|
return <CommentsFlatSkeleton />
|
||||||
}
|
}
|
||||||
const { notifications: { notifications, cursor } } = data
|
const { notifications: { notifications, cursor } } = data
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* XXX we shouldn't use the index but we don't have a unique id in this union yet */}
|
{/* XXX we shouldn't use the index but we don't have a unique id in this union yet */}
|
||||||
{notifications.map((n, i) => (
|
{notifications.map((n, i) => (
|
||||||
<div key={i}>
|
<div
|
||||||
{n.__typename === 'Votification' && <small className='font-weight-bold text-success'>your {n.item.title ? 'post' : 'reply'} stacked {n.earnedSats} sats</small>}
|
key={i}
|
||||||
|
className={styles.clickToContext}
|
||||||
|
onClick={() => {
|
||||||
|
if (n.__typename === 'Reply' || !n.item.title) {
|
||||||
|
router.push({
|
||||||
|
pathname: '/items/[id]',
|
||||||
|
query: { id: n.item.parentId, commentId: n.item.id }
|
||||||
|
}, `/items/${n.item.parentId}`)
|
||||||
|
} else {
|
||||||
|
router.push(`items/${n.item.id}`)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{n.__typename === 'Votification' && <small className='font-weight-bold text-success ml-2'>your {n.item.title ? 'post' : 'reply'} stacked {n.earnedSats} sats</small>}
|
||||||
<div className={n.__typename === 'Votification' ? 'ml-sm-4 ml-2' : ''}>
|
<div className={n.__typename === 'Votification' ? 'ml-sm-4 ml-2' : ''}>
|
||||||
{n.item.title
|
{n.item.title
|
||||||
? <Item item={n.item} />
|
? <Item item={n.item} />
|
||||||
|
9
components/notifications.module.css
Normal file
9
components/notifications.module.css
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.clickToContext {
|
||||||
|
border-radius: .4rem;
|
||||||
|
padding: .2rem 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clickToContext:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.03);
|
||||||
|
}
|
@ -39,7 +39,7 @@ export default function UserComments ({ user }) {
|
|||||||
<Layout noSeo>
|
<Layout noSeo>
|
||||||
<Seo user={user} />
|
<Seo user={user} />
|
||||||
<UserHeader user={user} />
|
<UserHeader user={user} />
|
||||||
<CommentsFlat variables={{ userId: user.id }} includeParent noReply clickToContext />
|
<CommentsFlat variables={{ userId: user.id }} includeParent noReply />
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ footer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.flash-it {
|
.flash-it {
|
||||||
animation: flash 2s linear 2;
|
animation: flash 2s linear 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user