diff --git a/api/resolvers/user.js b/api/resolvers/user.js index b4163775..f0e5dcec 100644 --- a/api/resolvers/user.js +++ b/api/resolvers/user.js @@ -149,6 +149,118 @@ export default { users } }, + hasNewNotes: async (parent, args, { me, models }) => { + if (!me) { + return false + } + const user = await models.user.findUnique({ where: { id: me.id } }) + const lastChecked = user.checkedNotesAt || new Date(0) + + // check if any votes have been cast for them since checkedNotesAt + if (user.noteItemSats) { + const votes = await models.$queryRaw(` + SELECT "ItemAct".id, "ItemAct".created_at + FROM "Item" + JOIN "ItemAct" on "ItemAct"."itemId" = "Item".id + WHERE "ItemAct"."userId" <> $1 + AND "ItemAct".created_at > $2 + AND "Item"."userId" = $1 + AND "ItemAct".act IN ('VOTE', 'TIP') + LIMIT 1`, me.id, lastChecked) + if (votes.length > 0) { + return true + } + } + + // check if they have any replies since checkedNotesAt + const newReplies = await models.$queryRaw(` + SELECT "Item".id, "Item".created_at + FROM "Item" + JOIN "Item" p ON ${user.noteAllDescendants ? '"Item".path <@ p.path' : '"Item"."parentId" = p.id'} + WHERE p."userId" = $1 + AND "Item".created_at > $2 AND "Item"."userId" <> $1 + ${await filterClause(me, models)} + LIMIT 1`, me.id, lastChecked) + if (newReplies.length > 0) { + return true + } + + // check if they have any mentions since checkedNotesAt + if (user.noteMentions) { + const newMentions = await models.$queryRaw(` + SELECT "Item".id, "Item".created_at + FROM "Mention" + JOIN "Item" ON "Mention"."itemId" = "Item".id + WHERE "Mention"."userId" = $1 + AND "Mention".created_at > $2 + AND "Item"."userId" <> $1 + LIMIT 1`, me.id, lastChecked) + if (newMentions.length > 0) { + return true + } + } + + const job = await models.item.findFirst({ + where: { + maxBid: { + not: null + }, + userId: me.id, + statusUpdatedAt: { + gt: lastChecked + } + } + }) + if (job) { + return true + } + + if (user.noteEarning) { + const earn = await models.earn.findFirst({ + where: { + userId: me.id, + createdAt: { + gt: lastChecked + }, + msats: { + gte: 1000 + } + } + }) + if (earn) { + return true + } + } + + if (user.noteDeposits) { + const invoice = await models.invoice.findFirst({ + where: { + userId: me.id, + confirmedAt: { + gt: lastChecked + } + } + }) + if (invoice) { + return true + } + } + + // check if new invites have been redeemed + if (user.noteInvites) { + const newInvitees = await models.$queryRaw(` + SELECT "Invite".id + FROM users JOIN "Invite" on users."inviteId" = "Invite".id + WHERE "Invite"."userId" = $1 + AND users.created_at > $2 + LIMIT 1`, me.id, lastChecked) + if (newInvitees.length > 0) { + return true + } + } + + return false + }, searchUsers: async (parent, { q, limit, similarity }, { models }) => { return await models.$queryRaw` SELECT * FROM users where id > 615 AND SIMILARITY(name, ${q}) > ${Number(similarity) || 0.1} ORDER BY SIMILARITY(name, ${q}) DESC LIMIT ${Number(limit) || 5}` @@ -362,114 +474,6 @@ export default { }).invites({ take: 1 }) return invites.length > 0 - }, - hasNewNotes: async (user, args, { me, models }) => { - const lastChecked = user.checkedNotesAt || new Date(0) - - // check if any votes have been cast for them since checkedNotesAt - if (user.noteItemSats) { - const votes = await models.$queryRaw(` - SELECT "ItemAct".id, "ItemAct".created_at - FROM "Item" - JOIN "ItemAct" on "ItemAct"."itemId" = "Item".id - WHERE "ItemAct"."userId" <> $1 - AND "ItemAct".created_at > $2 - AND "Item"."userId" = $1 - AND "ItemAct".act IN ('VOTE', 'TIP') - LIMIT 1`, me.id, lastChecked) - if (votes.length > 0) { - return true - } - } - - // check if they have any replies since checkedNotesAt - const newReplies = await models.$queryRaw(` - SELECT "Item".id, "Item".created_at - FROM "Item" - JOIN "Item" p ON ${user.noteAllDescendants ? '"Item".path <@ p.path' : '"Item"."parentId" = p.id'} - WHERE p."userId" = $1 - AND "Item".created_at > $2 AND "Item"."userId" <> $1 - ${await filterClause(me, models)} - LIMIT 1`, me.id, lastChecked) - if (newReplies.length > 0) { - return true - } - - // check if they have any mentions since checkedNotesAt - if (user.noteMentions) { - const newMentions = await models.$queryRaw(` - SELECT "Item".id, "Item".created_at - FROM "Mention" - JOIN "Item" ON "Mention"."itemId" = "Item".id - WHERE "Mention"."userId" = $1 - AND "Mention".created_at > $2 - AND "Item"."userId" <> $1 - LIMIT 1`, me.id, lastChecked) - if (newMentions.length > 0) { - return true - } - } - - const job = await models.item.findFirst({ - where: { - maxBid: { - not: null - }, - userId: me.id, - statusUpdatedAt: { - gt: lastChecked - } - } - }) - if (job) { - return true - } - - if (user.noteEarning) { - const earn = await models.earn.findFirst({ - where: { - userId: me.id, - createdAt: { - gt: lastChecked - }, - msats: { - gte: 1000 - } - } - }) - if (earn) { - return true - } - } - - if (user.noteDeposits) { - const invoice = await models.invoice.findFirst({ - where: { - userId: me.id, - confirmedAt: { - gt: lastChecked - } - } - }) - if (invoice) { - return true - } - } - - // check if new invites have been redeemed - if (user.noteInvites) { - const newInvitees = await models.$queryRaw(` - SELECT "Invite".id - FROM users JOIN "Invite" on users."inviteId" = "Invite".id - WHERE "Invite"."userId" = $1 - AND users.created_at > $2 - LIMIT 1`, me.id, lastChecked) - if (newInvitees.length > 0) { - return true - } - } - - return false } } } diff --git a/api/ssrApollo.js b/api/ssrApollo.js index c13792d5..3931c76d 100644 --- a/api/ssrApollo.js +++ b/api/ssrApollo.js @@ -8,7 +8,7 @@ import models from './models' import { print } from 'graphql' import lnd from './lnd' import search from './search' -import { ME_SSR } from '../fragments/users' +import { ME } from '../fragments/users' import { getPrice } from '../components/price' export default async function getSSRApolloClient (req, me = null) { @@ -40,7 +40,7 @@ export function getGetServerSideProps (query, variables = null, notFoundFunc, re const client = await getSSRApolloClient(req) const { data: { me } } = await client.query({ - query: ME_SSR + query: ME }) const price = await getPrice(me?.fiatCurrency) diff --git a/api/typeDefs/user.js b/api/typeDefs/user.js index f2c260c7..c6fffb6a 100644 --- a/api/typeDefs/user.js +++ b/api/typeDefs/user.js @@ -9,6 +9,7 @@ export default gql` nameAvailable(name: String!): Boolean! topUsers(cursor: String, when: String, sort: String): Users searchUsers(q: String!, limit: Int, similarity: Float): [User!]! + hasNewNotes: Boolean! } type Users { @@ -46,7 +47,6 @@ export default gql` spent(when: String): Int! freePosts: Int! freeComments: Int! - hasNewNotes: Boolean! hasInvites: Boolean! tipDefault: Int! fiatCurrency: String! diff --git a/components/header.js b/components/header.js index 1580dcfb..6e34a2b2 100644 --- a/components/header.js +++ b/components/header.js @@ -35,7 +35,11 @@ export default function Header ({ sub }) { subLatestPost(name: $name) } `, { variables: { name: 'jobs' }, pollInterval: 600000, fetchPolicy: 'network-only' }) - + const { data: hasNewNotes } = useQuery(gql` + { + hasNewNotes + } + `, { pollInterval: 30000, fetchPolicy: 'cache-and-network' }) const [lastCheckedJobs, setLastCheckedJobs] = useState(new Date().getTime()) useEffect(() => { if (me) { @@ -53,12 +57,12 @@ export default function Header ({ sub }) { return (