poll for notifications less, don't retry gql
This commit is contained in:
parent
9431469453
commit
8de00c741d
|
@ -149,6 +149,118 @@ export default {
|
||||||
users
|
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 }) => {
|
searchUsers: async (parent, { q, limit, similarity }, { models }) => {
|
||||||
return await models.$queryRaw`
|
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}`
|
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 })
|
}).invites({ take: 1 })
|
||||||
|
|
||||||
return invites.length > 0
|
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import models from './models'
|
||||||
import { print } from 'graphql'
|
import { print } from 'graphql'
|
||||||
import lnd from './lnd'
|
import lnd from './lnd'
|
||||||
import search from './search'
|
import search from './search'
|
||||||
import { ME_SSR } from '../fragments/users'
|
import { ME } from '../fragments/users'
|
||||||
import { getPrice } from '../components/price'
|
import { getPrice } from '../components/price'
|
||||||
|
|
||||||
export default async function getSSRApolloClient (req, me = null) {
|
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 client = await getSSRApolloClient(req)
|
||||||
|
|
||||||
const { data: { me } } = await client.query({
|
const { data: { me } } = await client.query({
|
||||||
query: ME_SSR
|
query: ME
|
||||||
})
|
})
|
||||||
|
|
||||||
const price = await getPrice(me?.fiatCurrency)
|
const price = await getPrice(me?.fiatCurrency)
|
||||||
|
|
|
@ -9,6 +9,7 @@ export default gql`
|
||||||
nameAvailable(name: String!): Boolean!
|
nameAvailable(name: String!): Boolean!
|
||||||
topUsers(cursor: String, when: String, sort: String): Users
|
topUsers(cursor: String, when: String, sort: String): Users
|
||||||
searchUsers(q: String!, limit: Int, similarity: Float): [User!]!
|
searchUsers(q: String!, limit: Int, similarity: Float): [User!]!
|
||||||
|
hasNewNotes: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Users {
|
type Users {
|
||||||
|
@ -46,7 +47,6 @@ export default gql`
|
||||||
spent(when: String): Int!
|
spent(when: String): Int!
|
||||||
freePosts: Int!
|
freePosts: Int!
|
||||||
freeComments: Int!
|
freeComments: Int!
|
||||||
hasNewNotes: Boolean!
|
|
||||||
hasInvites: Boolean!
|
hasInvites: Boolean!
|
||||||
tipDefault: Int!
|
tipDefault: Int!
|
||||||
fiatCurrency: String!
|
fiatCurrency: String!
|
||||||
|
|
|
@ -35,7 +35,11 @@ export default function Header ({ sub }) {
|
||||||
subLatestPost(name: $name)
|
subLatestPost(name: $name)
|
||||||
}
|
}
|
||||||
`, { variables: { name: 'jobs' }, pollInterval: 600000, fetchPolicy: 'network-only' })
|
`, { 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())
|
const [lastCheckedJobs, setLastCheckedJobs] = useState(new Date().getTime())
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (me) {
|
if (me) {
|
||||||
|
@ -53,12 +57,12 @@ export default function Header ({ sub }) {
|
||||||
return (
|
return (
|
||||||
<div className='d-flex align-items-center'>
|
<div className='d-flex align-items-center'>
|
||||||
<Head>
|
<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>
|
</Head>
|
||||||
<Link href='/notifications' passHref>
|
<Link href='/notifications' passHref>
|
||||||
<Nav.Link eventKey='notifications' className='pl-0 position-relative'>
|
<Nav.Link eventKey='notifications' className='pl-0 position-relative'>
|
||||||
<NoteIcon />
|
<NoteIcon />
|
||||||
{me?.hasNewNotes &&
|
{hasNewNotes?.hasNewNotes &&
|
||||||
<span className={styles.notification}>
|
<span className={styles.notification}>
|
||||||
<span className='invisible'>{' '}</span>
|
<span className='invisible'>{' '}</span>
|
||||||
</span>}
|
</span>}
|
||||||
|
|
|
@ -3,36 +3,6 @@ import { COMMENT_FIELDS } from './comments'
|
||||||
import { ITEM_FIELDS, ITEM_WITH_COMMENTS } from './items'
|
import { ITEM_FIELDS, ITEM_WITH_COMMENTS } from './items'
|
||||||
|
|
||||||
export const ME = gql`
|
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 {
|
me {
|
||||||
id
|
id
|
||||||
|
|
|
@ -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 { decodeCursor, LIMIT } from './cursor'
|
||||||
import { RetryLink } from '@apollo/client/link/retry'
|
// import { RetryLink } from '@apollo/client/link/retry'
|
||||||
|
|
||||||
const additiveLink = from([
|
// const additiveLink = from([
|
||||||
new RetryLink(),
|
// new RetryLink(),
|
||||||
new HttpLink({ uri: '/api/graphql' })
|
// new HttpLink({ uri: '/api/graphql' })
|
||||||
])
|
// ])
|
||||||
|
|
||||||
function isFirstPage (cursor, existingThings) {
|
function isFirstPage (cursor, existingThings) {
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
|
@ -20,7 +20,7 @@ function isFirstPage (cursor, existingThings) {
|
||||||
|
|
||||||
export default function getApolloClient () {
|
export default function getApolloClient () {
|
||||||
global.apolloClient ||= new ApolloClient({
|
global.apolloClient ||= new ApolloClient({
|
||||||
link: additiveLink,
|
link: new HttpLink({ uri: '/api/graphql' }),
|
||||||
cache: new InMemoryCache({
|
cache: new InMemoryCache({
|
||||||
typePolicies: {
|
typePolicies: {
|
||||||
Query: {
|
Query: {
|
||||||
|
|
Loading…
Reference in New Issue