From c8df41bfa548b8cf4d21f0e6922b4e0deab320d1 Mon Sep 17 00:00:00 2001 From: keyan Date: Tue, 17 Aug 2021 18:07:52 -0500 Subject: [PATCH] fix clickToContext issue for comments, fix non-inner joins, make notification query work --- api/models/index.js | 2 +- api/resolvers/notifications.js | 16 +++++++++------- api/resolvers/user.js | 24 +++++++++++++----------- api/typeDefs/item.js | 1 + components/comment.js | 18 +++++++++++++----- components/notifications.js | 20 +++++++++++++++----- fragments/notifications.js | 2 +- pages/_app.js | 18 ++++++++++++++++++ pages/notifications.js | 24 +++--------------------- 9 files changed, 74 insertions(+), 51 deletions(-) diff --git a/api/models/index.js b/api/models/index.js index 1312709e..e79851f2 100644 --- a/api/models/index.js +++ b/api/models/index.js @@ -1,7 +1,7 @@ import { PrismaClient } from '@prisma/client' const prisma = global.prisma || new PrismaClient({ - log: ['query', 'warn', 'error'] + log: ['warn', 'error'] }) if (process.env.NODE_ENV === 'development') global.prisma = prisma diff --git a/api/resolvers/notifications.js b/api/resolvers/notifications.js index 138b9146..eac7a6bb 100644 --- a/api/resolvers/notifications.js +++ b/api/resolvers/notifications.js @@ -1,3 +1,4 @@ +import { AuthenticationError } from 'apollo-server-micro' import { decodeCursor, LIMIT, nextCursorEncoded } from './cursor' export default { @@ -44,7 +45,8 @@ export default { let notifications = await models.$queryRaw(` SELECT ${ITEM_FIELDS}, "Item".created_at as sort_time, NULL as "earnedSats" From "Item" - JOIN "Item" p ON "Item"."parentId" = p.id AND p."userId" = $1 + JOIN "Item" p ON "Item"."parentId" = p.id + WHERE p."userId" = $1 AND "Item"."userId" <> $1 AND "Item".created_at <= $2 UNION ALL (SELECT ${ITEM_SUBQUERY_FIELDS}, max(subquery.voted_at) as sort_time, sum(subquery.sats) as "earnedSats" @@ -52,16 +54,16 @@ export default { (SELECT ${ITEM_FIELDS}, "Vote".created_at as voted_at, "Vote".sats, ROW_NUMBER() OVER(ORDER BY "Vote".created_at) - ROW_NUMBER() OVER(PARTITION BY "Item".id ORDER BY "Vote".created_at) as island - FROM "Item" - LEFT JOIN "Vote" on "Vote"."itemId" = "Item".id - AND "Vote"."userId" <> $1 + FROM "Vote" + JOIN "Item" on "Vote"."itemId" = "Item".id + WHERE "Vote"."userId" <> $1 AND "Item".created_at <= $2 AND "Vote".boost = false - WHERE "Item"."userId" = $1) subquery + AND "Item"."userId" = $1) subquery GROUP BY ${ITEM_SUBQUERY_FIELDS}, subquery.island ORDER BY max(subquery.voted_at) desc) ORDER BY sort_time DESC OFFSET $3 - LIMIT ${LIMIT}`, me ? me.id : 622, decodedCursor.time, decodedCursor.offset) + LIMIT ${LIMIT}`, 622, decodedCursor.time, decodedCursor.offset) notifications = notifications.map(n => { n.item = { ...n } @@ -85,4 +87,4 @@ const ITEM_SUBQUERY_FIELDS = const ITEM_FIELDS = `"Item".id, "Item".created_at as "createdAt", "Item".updated_at as "updatedAt", "Item".title, - "Item".text, "Item".url, "Item"."userId", "Item"."parentId", ltree2text("Item"."path") AS "path"` + "Item".text, "Item".url, "Item"."userId", "Item"."parentId", ltree2text("Item"."path") AS path` diff --git a/api/resolvers/user.js b/api/resolvers/user.js index 9a198482..92f84d13 100644 --- a/api/resolvers/user.js +++ b/api/resolvers/user.js @@ -25,12 +25,12 @@ export default { const [{ sum }] = await models.$queryRaw(` SELECT sum("Vote".sats) - FROM "Item" - LEFT JOIN "Vote" on "Vote"."itemId" = "Item".id - AND "Vote"."userId" <> $1 + FROM "Vote" + JOIN "Item" on "Vote"."itemId" = "Item".id + WHERE "Vote"."userId" <> $1 AND ("Vote".created_at > $2 OR $2 IS NULL) AND "Vote".boost = false - WHERE "Item"."userId" = $1`, user.id, user.checkedNotesAt) + AND "Item"."userId" = $1`, user.id, user.checkedNotesAt) await models.user.update({ where: { id: me.id }, data: { checkedNotesAt: new Date() } }) return sum || 0 @@ -64,9 +64,10 @@ export default { stacked: async (user, args, { models }) => { const [{ sum }] = await models.$queryRaw` SELECT sum("Vote".sats) - FROM "Item" - LEFT JOIN "Vote" on "Vote"."itemId" = "Item".id AND "Vote"."userId" <> ${user.id} AND boost = false - WHERE "Item"."userId" = ${user.id}` + FROM "Vote" + JOIN "Item" on "Vote"."itemId" = "Item".id + WHERE "Vote"."userId" <> ${user.id} AND boost = false + AND "Item"."userId" = ${user.id}` return sum || 0 }, sats: async (user, args, { models }) => { @@ -77,11 +78,11 @@ export default { const votes = await models.$queryRaw(` SELECT "Vote".id, "Vote".created_at FROM "Vote" - LEFT JOIN "Item" on "Vote"."itemId" = "Item".id - AND "Vote"."userId" <> $1 + JOIN "Item" on "Vote"."itemId" = "Item".id + WHERE "Vote"."userId" <> $1 AND ("Vote".created_at > $2 OR $2 IS NULL) AND "Vote".boost = false - WHERE "Item"."userId" = $1 + AND "Item"."userId" = $1 LIMIT 1`, user.id, user.checkedNotesAt) if (votes.length > 0) { return true @@ -91,7 +92,8 @@ export default { const newReplies = await models.$queryRaw(` SELECT "Item".id, "Item".created_at From "Item" - JOIN "Item" p ON "Item"."parentId" = p.id AND p."userId" = $1 + JOIN "Item" p ON "Item"."parentId" = p.id + WHERE p."userId" = $1 AND ("Item".created_at > $2 OR $2 IS NULL) AND "Item"."userId" <> $1 LIMIT 1`, user.id, user.checkedNotesAt) return !!newReplies.length diff --git a/api/typeDefs/item.js b/api/typeDefs/item.js index 99a4f111..c01a8378 100644 --- a/api/typeDefs/item.js +++ b/api/typeDefs/item.js @@ -44,5 +44,6 @@ export default gql` meSats: Int! ncomments: Int! comments: [Item!]! + path: String } ` diff --git a/components/comment.js b/components/comment.js index edd58068..5620cb2b 100644 --- a/components/comment.js +++ b/components/comment.js @@ -13,7 +13,7 @@ import { useMe } from './me' import CommentEdit from './comment-edit' import Countdown from './countdown' -function Parent ({ item }) { +function Parent ({ item, rootText }) { const ParentFrag = () => ( <> \ @@ -32,13 +32,13 @@ function Parent ({ item }) { {Number(item.root.id) !== Number(item.parentId) && } \ - e.stopPropagation()} className='text-reset'>root: {item.root.title} + e.stopPropagation()} className='text-reset'>{rootText || 'on:'} {item.root.title} ) } -export default function Comment ({ item, children, replyOpen, includeParent, cacheId, noComments, noReply, clickToContext }) { +export default function Comment ({ item, children, replyOpen, includeParent, rootText, noComments, noReply, clickToContext }) { const [reply, setReply] = useState(replyOpen) const [edit, setEdit] = useState() const [collapse, setCollapse] = useState(false) @@ -50,8 +50,11 @@ export default function Comment ({ item, children, replyOpen, includeParent, cac const [canEdit, setCanEdit] = useState(mine && (Date.now() < editThreshold)) + console.log('wtf router', router, item.id, ref.current) + useEffect(() => { if (Number(router.query.commentId) === Number(item.id)) { + console.log(ref.current.scrollTop) ref.current.scrollIntoView() // ref.current.classList.add('flash-it') } @@ -61,7 +64,12 @@ export default function Comment ({ item, children, replyOpen, includeParent, cac
{ if (clickToContext) { - router.push(`/items/${item.parentId}?commentId=${item.id}`, `/items/${item.parentId}`) + 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 : ''}`} > @@ -83,7 +91,7 @@ export default function Comment ({ item, children, replyOpen, includeParent, cac {timeSince(new Date(item.createdAt))} - {includeParent && } + {includeParent && }
{!includeParent && (collapse ? setCollapse(false)} /> diff --git a/components/notifications.js b/components/notifications.js index 58a9314f..ebce1242 100644 --- a/components/notifications.js +++ b/components/notifications.js @@ -2,20 +2,30 @@ import { useQuery } from '@apollo/client' import Button from 'react-bootstrap/Button' import { useState } from 'react' import Comment, { CommentSkeleton } from './comment' +import Item from './item' import { NOTIFICATIONS } from '../fragments/notifications' -export default function CommentsFlat ({ variables, ...props }) { - const { loading, error, data, fetchMore } = useQuery(NOTIFICATIONS) +export default function Notifications ({ variables, ...props }) { + const { loading, error, data, fetchMore } = useQuery(NOTIFICATIONS, { + variables + }) if (error) return
Failed to load!
if (loading) { return } - const { notifications: { notifications, cursor } } = data return ( <> - {notifications.map(item => ( - + {/* XXX we shouldn't use the index but we don't have a unique id in this union yet */} + {notifications.map((n, i) => ( +
+ {n.__typename === 'Votification' && your {n.item.title ? 'post' : 'reply'} stacked {n.earnedSats} sats} +
+ {n.item.title + ? + : } +
+
))} diff --git a/fragments/notifications.js b/fragments/notifications.js index 5e755867..fa26a739 100644 --- a/fragments/notifications.js +++ b/fragments/notifications.js @@ -1,4 +1,4 @@ -import { gql } from 'apollo-server-micro' +import { gql } from '@apollo/client' import { ITEM_FIELDS } from './items' export const NOTIFICATIONS = gql` diff --git a/pages/_app.js b/pages/_app.js index cb7d4eb0..51b0dc52 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -49,6 +49,24 @@ const client = new ApolloClient({ } } } + }, + notifications: { + merge (existing, incoming, { readField }) { + const notifications = existing ? existing.notifications : [] + return { + cursor: incoming.cursor, + notifications: [...notifications, ...incoming.notifications] + } + }, + + read (existing) { + if (existing) { + return { + cursor: existing.cursor, + notifications: existing.notifications + } + } + } } } } diff --git a/pages/notifications.js b/pages/notifications.js index d0f6f4f1..c15810a9 100644 --- a/pages/notifications.js +++ b/pages/notifications.js @@ -1,28 +1,10 @@ -import { gql, useQuery } from '@apollo/client' -import CommentsFlat from '../components/comments-flat' import Layout from '../components/layout' +import Notifications from '../components/notifications' -export function RecentlyStacked () { - const query = gql` - { - recentlyStacked - }` - const { data } = useQuery(query) - if (!data || !data.recentlyStacked) return null - - return ( -

- you stacked {data.recentlyStacked} sats -

- ) -} - -export default function Notifications ({ user }) { +export default function NotificationPage () { return ( - -
replies
- +
) }