Notifications for when you are forwarded sats from a post (#467)
* Notifications for when you are forwarded sats from a post Support notifications when a post for which you are forwarded gets zapped This is controlled by a new boolean flag in user settings * Send push notifications to forwarded users when they get forwarded sats * Add `Promise.allSettled` per PR feedback * Remove `FEE` act type when building forwarded zaps notifications Don't include `FEE` actions, only `TIP` actions to avoid "0 sats forwarded" notifications --------- Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
This commit is contained in:
parent
9064224fd3
commit
94fbabcdf9
|
@ -812,6 +812,16 @@ export default {
|
|||
item: updatedItem,
|
||||
tag: `TIP-${updatedItem.id}`
|
||||
})
|
||||
|
||||
// send push notifications to forwarded recipients
|
||||
if (mappedForwards.length) {
|
||||
await Promise.allSettled(mappedForwards.map(forward => sendUserNotification(forward.user.id, {
|
||||
title: `you were forwarded ${numWithUnits(msatsToSats(updatedItem.msats) * forward.pct / 100)}`,
|
||||
body: updatedItem.title ?? updatedItem.text,
|
||||
item: updatedItem,
|
||||
tag: `FORWARDEDTIP-${updatedItem.id}`
|
||||
})))
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
|
|
|
@ -176,6 +176,23 @@ export default {
|
|||
)
|
||||
}
|
||||
|
||||
if (meFull.noteForwardedSats) {
|
||||
queries.push(
|
||||
`(SELECT "Item".id::TEXT, MAX("ItemAct".created_at) AS "sortTime",
|
||||
MAX("Item".msats / 1000 * "ItemForward".pct / 100) as "earnedSats", 'ForwardedVotification' AS type
|
||||
FROM "Item"
|
||||
JOIN "ItemAct" ON "ItemAct"."itemId" = "Item".id
|
||||
JOIN "ItemForward" ON "ItemForward"."itemId" = "Item".id AND "ItemForward"."userId" = $1
|
||||
WHERE "ItemAct"."userId" <> $1
|
||||
AND "Item"."userId" <> $1
|
||||
AND "ItemAct".created_at <= $2
|
||||
AND "ItemAct".act IN ('TIP')
|
||||
GROUP BY "Item".id
|
||||
ORDER BY "sortTime" DESC
|
||||
LIMIT ${LIMIT}+$3)`
|
||||
)
|
||||
}
|
||||
|
||||
if (meFull.noteDeposits) {
|
||||
queries.push(
|
||||
`(SELECT "Invoice".id::text, "Invoice"."confirmedAt" AS "sortTime", FLOOR("msatsReceived" / 1000) as "earnedSats",
|
||||
|
@ -310,6 +327,9 @@ export default {
|
|||
Votification: {
|
||||
item: async (n, args, { models, me }) => getItem(n, { id: n.id }, { models, me })
|
||||
},
|
||||
ForwardedVotification: {
|
||||
item: async (n, args, { models, me }) => getItem(n, { id: n.id }, { models, me })
|
||||
},
|
||||
Reply: {
|
||||
item: async (n, args, { models, me }) => getItem(n, { id: n.id }, { models, me })
|
||||
},
|
||||
|
|
|
@ -344,6 +344,25 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
if (user.noteForwardedSats) {
|
||||
const votes = await models.$queryRawUnsafe(`
|
||||
SELECT 1
|
||||
FROM "Item"
|
||||
JOIN "ItemAct" ON
|
||||
"ItemAct"."itemId" = "Item".id
|
||||
AND "ItemAct"."userId" <> "Item"."userId"
|
||||
JOIN "ItemForward" ON
|
||||
"ItemForward"."itemId" = "Item".id
|
||||
AND "ItemForward"."userId" = $1
|
||||
WHERE "ItemAct".created_at > $2
|
||||
AND "Item"."userId" <> $1
|
||||
AND "ItemAct".act = 'TIP'
|
||||
LIMIT 1`, me.id, lastChecked)
|
||||
if (votes.length > 0) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
const job = await models.item.findFirst({
|
||||
where: {
|
||||
maxBid: {
|
||||
|
|
|
@ -17,6 +17,13 @@ export default gql`
|
|||
sortTime: Date!
|
||||
}
|
||||
|
||||
type ForwardedVotification {
|
||||
id: ID!
|
||||
earnedSats: Int!
|
||||
item: Item!
|
||||
sortTime: Date!
|
||||
}
|
||||
|
||||
type FollowActivity {
|
||||
id: ID!
|
||||
item: Item!
|
||||
|
@ -84,7 +91,7 @@ export default gql`
|
|||
|
||||
union Notification = Reply | Votification | Mention
|
||||
| Invitification | Earn | JobChanged | InvoicePaid | Referral
|
||||
| Streak | FollowActivity
|
||||
| Streak | FollowActivity | ForwardedVotification
|
||||
|
||||
type Notifications {
|
||||
lastChecked: Date
|
||||
|
|
|
@ -24,7 +24,8 @@ export default gql`
|
|||
noteEarning: Boolean!, noteAllDescendants: Boolean!, noteMentions: Boolean!, noteDeposits: Boolean!,
|
||||
noteInvites: Boolean!, noteJobIndicator: Boolean!, noteCowboyHat: Boolean!, hideInvoiceDesc: Boolean!,
|
||||
hideFromTopUsers: Boolean!, hideCowboyHat: Boolean!, clickToLoadImg: Boolean!,
|
||||
wildWestMode: Boolean!, greeterMode: Boolean!, nostrPubkey: String, nostrRelays: [String!], hideBookmarks: Boolean!): User
|
||||
wildWestMode: Boolean!, greeterMode: Boolean!, nostrPubkey: String, nostrRelays: [String!], hideBookmarks: Boolean!,
|
||||
noteForwardedSats: Boolean!): User
|
||||
setPhoto(photoId: ID!): Int!
|
||||
upsertBio(bio: String!): User!
|
||||
setWalkthrough(tipPopover: Boolean, upvotePopover: Boolean): Boolean
|
||||
|
@ -78,6 +79,7 @@ export default gql`
|
|||
noteInvites: Boolean!
|
||||
noteJobIndicator: Boolean!
|
||||
noteCowboyHat: Boolean!
|
||||
noteForwardedSats: Boolean!
|
||||
hideInvoiceDesc: Boolean!
|
||||
hideFromTopUsers: Boolean!
|
||||
hideCowboyHat: Boolean!
|
||||
|
|
|
@ -36,7 +36,8 @@ const createUserFilter = (tag) => {
|
|||
const tagMap = {
|
||||
REPLY: 'noteAllDescendants',
|
||||
MENTION: 'noteMentions',
|
||||
TIP: 'noteItemSats'
|
||||
TIP: 'noteItemSats',
|
||||
FORWARDEDTIP: 'noteForwardedSats'
|
||||
}
|
||||
const key = tagMap[tag.split('-')[0]]
|
||||
return key ? { user: { [key]: true } } : undefined
|
||||
|
|
|
@ -38,6 +38,7 @@ function Notification ({ n, fresh }) {
|
|||
(type === 'Referral' && <Referral n={n} />) ||
|
||||
(type === 'Streak' && <Streak n={n} />) ||
|
||||
(type === 'Votification' && <Votification n={n} />) ||
|
||||
(type === 'ForwardedVotification' && <ForwardedVotification n={n} />) ||
|
||||
(type === 'Mention' && <Mention n={n} />) ||
|
||||
(type === 'JobChanged' && <JobChanged n={n} />) ||
|
||||
(type === 'Reply' && <Reply n={n} />) ||
|
||||
|
@ -291,6 +292,27 @@ function Votification ({ n }) {
|
|||
)
|
||||
}
|
||||
|
||||
function ForwardedVotification ({ n }) {
|
||||
return (
|
||||
<>
|
||||
<small className='fw-bold text-success d-inline-block ms-2 my-1' style={{ lineHeight: '1.25' }}>
|
||||
you were forwarded {numWithUnits(n.earnedSats, { abbreviate: false })} from
|
||||
</small>
|
||||
<div>
|
||||
{n.item.title
|
||||
? <Item item={n.item} />
|
||||
: (
|
||||
<div className='pb-2'>
|
||||
<RootProvider root={n.item.root}>
|
||||
<Comment item={n.item} noReply includeParent clickToContext />
|
||||
</RootProvider>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function Mention ({ n }) {
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -32,6 +32,15 @@ export const NOTIFICATIONS = gql`
|
|||
text
|
||||
}
|
||||
}
|
||||
... on ForwardedVotification {
|
||||
id
|
||||
sortTime
|
||||
earnedSats
|
||||
item {
|
||||
...ItemFullFields
|
||||
text
|
||||
}
|
||||
}
|
||||
... on Streak {
|
||||
id
|
||||
sortTime
|
||||
|
|
|
@ -26,6 +26,7 @@ export const ME = gql`
|
|||
noteInvites
|
||||
noteJobIndicator
|
||||
noteCowboyHat
|
||||
noteForwardedSats
|
||||
hideInvoiceDesc
|
||||
hideFromTopUsers
|
||||
hideCowboyHat
|
||||
|
@ -50,6 +51,7 @@ export const SETTINGS_FIELDS = gql`
|
|||
noteInvites
|
||||
noteJobIndicator
|
||||
noteCowboyHat
|
||||
noteForwardedSats
|
||||
hideInvoiceDesc
|
||||
hideFromTopUsers
|
||||
hideCowboyHat
|
||||
|
@ -83,13 +85,15 @@ mutation setSettings($tipDefault: Int!, $turboTipping: Boolean!, $fiatCurrency:
|
|||
$noteEarning: Boolean!, $noteAllDescendants: Boolean!, $noteMentions: Boolean!, $noteDeposits: Boolean!,
|
||||
$noteInvites: Boolean!, $noteJobIndicator: Boolean!, $noteCowboyHat: Boolean!, $hideInvoiceDesc: Boolean!,
|
||||
$hideFromTopUsers: Boolean!, $hideCowboyHat: Boolean!, $clickToLoadImg: Boolean!,
|
||||
$wildWestMode: Boolean!, $greeterMode: Boolean!, $nostrPubkey: String, $nostrRelays: [String!], $hideBookmarks: Boolean!) {
|
||||
$wildWestMode: Boolean!, $greeterMode: Boolean!, $nostrPubkey: String, $nostrRelays: [String!], $hideBookmarks: Boolean!,
|
||||
$noteForwardedSats: Boolean!) {
|
||||
setSettings(tipDefault: $tipDefault, turboTipping: $turboTipping, fiatCurrency: $fiatCurrency,
|
||||
noteItemSats: $noteItemSats, noteEarning: $noteEarning, noteAllDescendants: $noteAllDescendants,
|
||||
noteMentions: $noteMentions, noteDeposits: $noteDeposits, noteInvites: $noteInvites,
|
||||
noteJobIndicator: $noteJobIndicator, noteCowboyHat: $noteCowboyHat, hideInvoiceDesc: $hideInvoiceDesc,
|
||||
hideFromTopUsers: $hideFromTopUsers, hideCowboyHat: $hideCowboyHat, clickToLoadImg: $clickToLoadImg,
|
||||
wildWestMode: $wildWestMode, greeterMode: $greeterMode, nostrPubkey: $nostrPubkey, nostrRelays: $nostrRelays, hideBookmarks: $hideBookmarks) {
|
||||
wildWestMode: $wildWestMode, greeterMode: $greeterMode, nostrPubkey: $nostrPubkey, nostrRelays: $nostrRelays, hideBookmarks: $hideBookmarks,
|
||||
noteForwardedSats: $noteForwardedSats) {
|
||||
...SettingsFields
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ export default function Settings ({ ssrData }) {
|
|||
noteInvites: settings?.noteInvites,
|
||||
noteJobIndicator: settings?.noteJobIndicator,
|
||||
noteCowboyHat: settings?.noteCowboyHat,
|
||||
noteForwardedSats: settings?.noteForwardedSats,
|
||||
hideInvoiceDesc: settings?.hideInvoiceDesc,
|
||||
hideFromTopUsers: settings?.hideFromTopUsers,
|
||||
hideCowboyHat: settings?.hideCowboyHat,
|
||||
|
@ -160,6 +161,11 @@ export default function Settings ({ ssrData }) {
|
|||
name='noteItemSats'
|
||||
groupClassName='mb-0'
|
||||
/>
|
||||
<Checkbox
|
||||
label='I get forwarded sats from a post'
|
||||
name='noteForwardedSats'
|
||||
groupClassName='mb-0'
|
||||
/>
|
||||
<Checkbox
|
||||
label='I get a daily airdrop'
|
||||
name='noteEarning'
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "users" ADD COLUMN "noteForwardedSats" BOOLEAN NOT NULL DEFAULT true;
|
|
@ -39,6 +39,7 @@ model User {
|
|||
noteInvites Boolean @default(true)
|
||||
noteItemSats Boolean @default(true)
|
||||
noteMentions Boolean @default(true)
|
||||
noteForwardedSats Boolean @default(true)
|
||||
lastCheckedJobs DateTime?
|
||||
noteJobIndicator Boolean @default(true)
|
||||
photoId Int?
|
||||
|
|
Loading…
Reference in New Issue