Add withdrawal notifications
This commit is contained in:
parent
2f818fc968
commit
3388f818cf
@ -1,7 +1,7 @@
|
||||
import { GraphQLError } from 'graphql'
|
||||
import { decodeCursor, LIMIT, nextNoteCursorEncoded } from '@/lib/cursor'
|
||||
import { getItem, filterClause, whereClause, muteClause } from './item'
|
||||
import { getInvoice } from './wallet'
|
||||
import { getInvoice, getWithdrawal } from './wallet'
|
||||
import { pushSubscriptionSchema, ssValidate } from '@/lib/validate'
|
||||
import { replyToSubscription } from '@/lib/webPush'
|
||||
import { getSub } from './sub'
|
||||
@ -221,6 +221,19 @@ export default {
|
||||
)
|
||||
}
|
||||
|
||||
if (meFull.noteWithdrawals) {
|
||||
queries.push(
|
||||
`(SELECT "Withdrawl".id::text, "Withdrawl".created_at AS "sortTime", FLOOR("msatsPaid" / 1000) as "earnedSats",
|
||||
'WithdrawlPaid' AS type
|
||||
FROM "Withdrawl"
|
||||
WHERE "Withdrawl"."userId" = $1
|
||||
AND status = 'CONFIRMED'
|
||||
AND created_at < $2
|
||||
ORDER BY "sortTime" DESC
|
||||
LIMIT ${LIMIT})`
|
||||
)
|
||||
}
|
||||
|
||||
if (meFull.noteInvites) {
|
||||
queries.push(
|
||||
`(SELECT "Invite".id, MAX(users.created_at) AS "sortTime", NULL as "earnedSats",
|
||||
@ -430,6 +443,9 @@ export default {
|
||||
InvoicePaid: {
|
||||
invoice: async (n, args, { me, models }) => getInvoice(n, { id: n.id }, { me, models })
|
||||
},
|
||||
WithdrawlPaid: {
|
||||
withdrawl: async (n, args, { me, models }) => getWithdrawal(n, { id: n.id }, { me, models })
|
||||
},
|
||||
Invitification: {
|
||||
invite: async (n, args, { models }) => {
|
||||
return await models.invite.findUnique({
|
||||
|
@ -353,6 +353,22 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
if (user.noteWithdrawals) {
|
||||
const wdrwl = await models.withdrawl.findFirst({
|
||||
where: {
|
||||
userId: me.id,
|
||||
status: 'CONFIRMED',
|
||||
updatedAt: {
|
||||
gt: lastChecked
|
||||
}
|
||||
}
|
||||
})
|
||||
if (wdrwl) {
|
||||
foundNotes()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// check if new invites have been redeemed
|
||||
if (user.noteInvites) {
|
||||
const [newInvites] = await models.$queryRawUnsafe(`
|
||||
|
@ -53,6 +53,31 @@ export async function getInvoice (parent, { id }, { me, models, lnd }) {
|
||||
return inv
|
||||
}
|
||||
|
||||
export async function getWithdrawal (parent, { id }, { me, models }) {
|
||||
if (!me) {
|
||||
throw new GraphQLError('you must be logged in', { extensions: { code: 'FORBIDDEN' } })
|
||||
}
|
||||
|
||||
const wdrwl = await models.withdrawl.findUnique({
|
||||
where: {
|
||||
id: Number(id)
|
||||
},
|
||||
include: {
|
||||
user: true
|
||||
}
|
||||
})
|
||||
|
||||
if (!wdrwl) {
|
||||
throw new GraphQLError('withdrawal not found', { extensions: { code: 'BAD_INPUT' } })
|
||||
}
|
||||
|
||||
if (wdrwl.user.id !== me.id) {
|
||||
throw new GraphQLError('not ur withdrawal', { extensions: { code: 'FORBIDDEN' } })
|
||||
}
|
||||
|
||||
return wdrwl
|
||||
}
|
||||
|
||||
export function createHmac (hash) {
|
||||
const key = Buffer.from(process.env.INVOICE_HMAC_KEY, 'hex')
|
||||
return crypto.createHmac('sha256', key).update(Buffer.from(hash, 'hex')).digest('hex')
|
||||
@ -97,26 +122,7 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
withdrawl: async (parent, { id }, { me, models, lnd }) => {
|
||||
if (!me) {
|
||||
throw new GraphQLError('you must be logged in', { extensions: { code: 'FORBIDDEN' } })
|
||||
}
|
||||
|
||||
const wdrwl = await models.withdrawl.findUnique({
|
||||
where: {
|
||||
id: Number(id)
|
||||
},
|
||||
include: {
|
||||
user: true
|
||||
}
|
||||
})
|
||||
|
||||
if (wdrwl.user.id !== me.id) {
|
||||
throw new GraphQLError('not ur withdrawal', { extensions: { code: 'FORBIDDEN' } })
|
||||
}
|
||||
|
||||
return wdrwl
|
||||
},
|
||||
withdrawl: getWithdrawal,
|
||||
numBolt11s: async (parent, args, { me, models, lnd }) => {
|
||||
if (!me) {
|
||||
throw new GraphQLError('you must be logged in', { extensions: { code: 'FORBIDDEN' } })
|
||||
|
@ -91,6 +91,13 @@ export default gql`
|
||||
sortTime: Date!
|
||||
}
|
||||
|
||||
type WithdrawlPaid {
|
||||
id: ID!
|
||||
earnedSats: Int!
|
||||
withdrawl: Withdrawl!
|
||||
sortTime: Date!
|
||||
}
|
||||
|
||||
type Referral {
|
||||
id: ID!
|
||||
sortTime: Date!
|
||||
@ -115,7 +122,7 @@ export default gql`
|
||||
}
|
||||
|
||||
union Notification = Reply | Votification | Mention
|
||||
| Invitification | Earn | JobChanged | InvoicePaid | Referral
|
||||
| Invitification | Earn | JobChanged | InvoicePaid | WithdrawlPaid | Referral
|
||||
| Streak | FollowActivity | ForwardedVotification | Revenue | SubStatus
|
||||
| TerritoryPost | TerritoryTransfer
|
||||
|
||||
|
@ -82,7 +82,8 @@ export default gql`
|
||||
nostrRelays: [String!]
|
||||
noteAllDescendants: Boolean!
|
||||
noteCowboyHat: Boolean!
|
||||
noteDeposits: Boolean!
|
||||
noteDeposits: Boolean!,
|
||||
noteWithdrawals: Boolean!,
|
||||
noteEarning: Boolean!
|
||||
noteForwardedSats: Boolean!
|
||||
noteInvites: Boolean!
|
||||
@ -148,6 +149,7 @@ export default gql`
|
||||
noteAllDescendants: Boolean!
|
||||
noteCowboyHat: Boolean!
|
||||
noteDeposits: Boolean!
|
||||
noteWithdrawals: Boolean!
|
||||
noteEarning: Boolean!
|
||||
noteForwardedSats: Boolean!
|
||||
noteInvites: Boolean!
|
||||
|
@ -40,6 +40,7 @@ function Notification ({ n, fresh }) {
|
||||
(type === 'Revenue' && <RevenueNotification n={n} />) ||
|
||||
(type === 'Invitification' && <Invitification n={n} />) ||
|
||||
(type === 'InvoicePaid' && (n.invoice.nostr ? <NostrZap n={n} /> : <InvoicePaid n={n} />)) ||
|
||||
(type === 'WithdrawlPaid' && <WithdrawlPaid n={n} />) ||
|
||||
(type === 'Referral' && <Referral n={n} />) ||
|
||||
(type === 'Streak' && <Streak n={n} />) ||
|
||||
(type === 'Votification' && <Votification n={n} />) ||
|
||||
@ -95,6 +96,7 @@ const defaultOnClick = n => {
|
||||
if (type === 'SubStatus') return { href: `/~${n.sub.name}` }
|
||||
if (type === 'Invitification') return { href: '/invites' }
|
||||
if (type === 'InvoicePaid') return { href: `/invoices/${n.invoice.id}` }
|
||||
if (type === 'WithdrawlPaid') return { href: `/withdrawals/${n.withdrawl.id}` }
|
||||
if (type === 'Referral') return { href: '/referrals/month' }
|
||||
if (type === 'Streak') return {}
|
||||
if (type === 'TerritoryTransfer') return { href: `/~${n.sub.name}` }
|
||||
@ -277,6 +279,15 @@ function InvoicePaid ({ n }) {
|
||||
)
|
||||
}
|
||||
|
||||
function WithdrawlPaid ({ n }) {
|
||||
return (
|
||||
<div className='fw-bold text-info ms-2 py-1'>
|
||||
<Check className='fill-info me-1' />{numWithUnits(n.earnedSats, { abbreviate: false, unitSingular: 'sat was', unitPlural: 'sats were' })} withdrawn from your account
|
||||
<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function Referral ({ n }) {
|
||||
return (
|
||||
<small className='fw-bold text-secondary ms-2'>
|
||||
|
@ -133,6 +133,15 @@ export const NOTIFICATIONS = gql`
|
||||
lud18Data
|
||||
}
|
||||
}
|
||||
... on WithdrawlPaid {
|
||||
id
|
||||
sortTime
|
||||
earnedSats
|
||||
withdrawl {
|
||||
id
|
||||
satsPaid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} `
|
||||
|
@ -30,6 +30,7 @@ export const ME = gql`
|
||||
noteAllDescendants
|
||||
noteCowboyHat
|
||||
noteDeposits
|
||||
noteWithdrawals
|
||||
noteEarning
|
||||
noteForwardedSats
|
||||
noteInvites
|
||||
@ -72,6 +73,7 @@ export const SETTINGS_FIELDS = gql`
|
||||
noteAllDescendants
|
||||
noteMentions
|
||||
noteDeposits
|
||||
noteWithdrawals
|
||||
noteInvites
|
||||
noteJobIndicator
|
||||
noteCowboyHat
|
||||
|
@ -43,6 +43,7 @@ const createUserFilter = (tag) => {
|
||||
INVITE: 'noteInvites',
|
||||
EARN: 'noteEarning',
|
||||
DEPOSIT: 'noteDeposits',
|
||||
WITHDRAWAL: 'noteWithdrawals',
|
||||
STREAK: 'noteCowboyHat'
|
||||
}
|
||||
const key = tagMap[tag.split('-')[0]]
|
||||
|
@ -75,6 +75,7 @@ export default function Settings ({ ssrData }) {
|
||||
noteAllDescendants: settings?.noteAllDescendants,
|
||||
noteMentions: settings?.noteMentions,
|
||||
noteDeposits: settings?.noteDeposits,
|
||||
noteWithdrawals: settings?.noteWithdrawals,
|
||||
noteInvites: settings?.noteInvites,
|
||||
noteJobIndicator: settings?.noteJobIndicator,
|
||||
noteCowboyHat: settings?.noteCowboyHat,
|
||||
@ -223,6 +224,11 @@ export default function Settings ({ ssrData }) {
|
||||
name='noteDeposits'
|
||||
groupClassName='mb-0'
|
||||
/>
|
||||
<Checkbox
|
||||
label='sats are withdrawn from my account'
|
||||
name='noteWithdrawals'
|
||||
groupClassName='mb-0'
|
||||
/>
|
||||
<Checkbox
|
||||
label='someone mentions me'
|
||||
name='noteMentions'
|
||||
|
@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "users" ADD COLUMN "noteWithdrawals" BOOLEAN NOT NULL DEFAULT true;
|
@ -38,6 +38,7 @@ model User {
|
||||
stackedMsats BigInt @default(0)
|
||||
noteAllDescendants Boolean @default(true)
|
||||
noteDeposits Boolean @default(true)
|
||||
noteWithdrawals Boolean @default(true)
|
||||
noteEarning Boolean @default(true)
|
||||
noteInvites Boolean @default(true)
|
||||
noteItemSats Boolean @default(true)
|
||||
|
Loading…
x
Reference in New Issue
Block a user