poll for notifications less, don't retry gql

This commit is contained in:
keyan 2022-11-07 17:31:29 -06:00
parent 32651bea92
commit f1a4e9c682
6 changed files with 129 additions and 151 deletions

View File

@ -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
}
}
}

View File

@ -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)

View File

@ -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!

View File

@ -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 (
<div className='d-flex align-items-center'>
<Head>
<link rel='shortcut icon' href={me?.hasNewNotes ? '/favicon-notify.png' : '/favicon.png'} />
<link rel='shortcut icon' href={hasNewNotes?.hasNewNotes ? '/favicon-notify.png' : '/favicon.png'} />
</Head>
<Link href='/notifications' passHref>
<Nav.Link eventKey='notifications' className='pl-0 position-relative'>
<NoteIcon />
{me?.hasNewNotes &&
{hasNewNotes?.hasNewNotes &&
<span className={styles.notification}>
<span className='invisible'>{' '}</span>
</span>}

View File

@ -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

View File

@ -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: {