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 (
- + - {me?.hasNewNotes && + {hasNewNotes?.hasNewNotes && {' '} } diff --git a/fragments/users.js b/fragments/users.js index db4e1e16..5b98bc98 100644 --- a/fragments/users.js +++ b/fragments/users.js @@ -3,36 +3,6 @@ import { COMMENT_FIELDS } from './comments' import { ITEM_FIELDS, ITEM_WITH_COMMENTS } from './items' export const ME = gql` - { - me { - id - name - sats - stacked - freePosts - freeComments - hasNewNotes - tipDefault - fiatCurrency - bioId - hasInvites - upvotePopover - tipPopover - noteItemSats - noteEarning - noteAllDescendants - noteMentions - noteDeposits - noteInvites - noteJobIndicator - hideInvoiceDesc - wildWestMode - greeterMode - lastCheckedJobs - } - }` - -export const ME_SSR = gql` { me { id diff --git a/lib/apollo.js b/lib/apollo.js index 5829c368..291e3d2f 100644 --- a/lib/apollo.js +++ b/lib/apollo.js @@ -1,11 +1,11 @@ -import { ApolloClient, InMemoryCache, from, HttpLink } from '@apollo/client' +import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client' import { decodeCursor, LIMIT } from './cursor' -import { RetryLink } from '@apollo/client/link/retry' +// import { RetryLink } from '@apollo/client/link/retry' -const additiveLink = from([ - new RetryLink(), - new HttpLink({ uri: '/api/graphql' }) -]) +// const additiveLink = from([ +// new RetryLink(), +// new HttpLink({ uri: '/api/graphql' }) +// ]) function isFirstPage (cursor, existingThings) { if (cursor) { @@ -20,7 +20,7 @@ function isFirstPage (cursor, existingThings) { export default function getApolloClient () { global.apolloClient ||= new ApolloClient({ - link: additiveLink, + link: new HttpLink({ uri: '/api/graphql' }), cache: new InMemoryCache({ typePolicies: { Query: {