Add notification for bounty award as tip

This commit is contained in:
Ian Philips 2022-09-27 19:37:04 -04:00
parent b8f9f791b9
commit 353648566f
4 changed files with 64 additions and 7 deletions

View File

@ -1046,3 +1046,47 @@ export const createContractResolvedNotifications = async (
) )
) )
} }
export const createBountyNotification = async (
fromUser: User,
toUserId: string,
amount: number,
idempotencyKey: string,
contract: Contract,
commentId?: string
) => {
const privateUser = await getPrivateUser(toUserId)
if (!privateUser) return
const { sendToBrowser } = getNotificationDestinationsForUser(
privateUser,
'tip_received'
)
if (!sendToBrowser) return
const slug = commentId
const notificationRef = firestore
.collection(`/users/${toUserId}/notifications`)
.doc(idempotencyKey)
const notification: Notification = {
id: idempotencyKey,
userId: toUserId,
reason: 'tip_received',
createdTime: Date.now(),
isSeen: false,
sourceId: commentId ? commentId : contract.id,
sourceType: 'tip',
sourceUpdateType: 'created',
sourceUserName: fromUser.name,
sourceUserUsername: fromUser.username,
sourceUserAvatarUrl: fromUser.avatarUrl,
sourceText: amount.toString(),
sourceContractCreatorUsername: contract.creatorUsername,
sourceContractTitle: contract.question,
sourceContractSlug: contract.slug,
sourceSlug: slug,
sourceTitle: contract.question,
}
return await notificationRef.set(removeUndefinedProps(notification))
// maybe TODO: send email notification to comment creator
}

View File

@ -13,6 +13,7 @@ import { isProd } from './utils'
import { CommentBountyDepositTxn, CommentBountyWithdrawalTxn } from 'common/txn' import { CommentBountyDepositTxn, CommentBountyWithdrawalTxn } from 'common/txn'
import { runTxn } from 'functions/src/transact' import { runTxn } from 'functions/src/transact'
import { Comment } from 'common/comment' import { Comment } from 'common/comment'
import { createBountyNotification } from 'functions/src/create-notification'
const bodySchema = z.object({ const bodySchema = z.object({
contractId: z.string(), contractId: z.string(),
@ -78,7 +79,7 @@ export const awardcommentbounty = newEndpoint({}, async (req, auth) => {
if (!isFinite(amount)) throw new APIError(400, 'Invalid amount') if (!isFinite(amount)) throw new APIError(400, 'Invalid amount')
// run as transaction to prevent race conditions // run as transaction to prevent race conditions
return await firestore.runTransaction(async (transaction) => { const res = await firestore.runTransaction(async (transaction) => {
const userDoc = firestore.doc(`users/${auth.uid}`) const userDoc = firestore.doc(`users/${auth.uid}`)
const userSnap = await transaction.get(userDoc) const userSnap = await transaction.get(userDoc)
if (!userSnap.exists) throw new APIError(400, 'User not found') if (!userSnap.exists) throw new APIError(400, 'User not found')
@ -138,8 +139,21 @@ export const awardcommentbounty = newEndpoint({}, async (req, auth) => {
}) })
) )
return result return { ...result, comment, contract, user }
}) })
if (res.txn?.id) {
const { comment, contract, user } = res
await createBountyNotification(
user,
comment.userId,
amount,
res.txn.id,
contract,
comment.id
)
}
return res
}) })
const firestore = admin.firestore() const firestore = admin.firestore()

View File

@ -7,14 +7,13 @@ import { Row } from './layout/row'
import { Contract } from 'common/contract' import { Contract } from 'common/contract'
import { TextButton } from 'web/components/text-button' import { TextButton } from 'web/components/text-button'
import { COMMENT_BOUNTY_AMOUNT } from 'common/economy' import { COMMENT_BOUNTY_AMOUNT } from 'common/economy'
import { formatMoney } from 'common/util/format'
export function AwardBountyButton(prop: { export function AwardBountyButton(prop: {
comment: ContractComment comment: ContractComment
contract: Contract contract: Contract
}) { }) {
const { comment, contract } = prop const { comment, contract } = prop
const { bountiesAwarded } = comment
const amountAwarded = bountiesAwarded ?? 0
const me = useUser() const me = useUser()
@ -39,7 +38,7 @@ export function AwardBountyButton(prop: {
return ( return (
<Row className={clsx('-ml-2 items-center gap-0.5', !canUp ? '-ml-6' : '')}> <Row className={clsx('-ml-2 items-center gap-0.5', !canUp ? '-ml-6' : '')}>
<TextButton className={'font-bold'} onClick={submit}> <TextButton className={'font-bold'} onClick={submit}>
Award Award {formatMoney(COMMENT_BOUNTY_AMOUNT)}
</TextButton> </TextButton>
</Row> </Row>
) )

View File

@ -24,9 +24,9 @@ import {
HOUSE_LIQUIDITY_PROVIDER_ID, HOUSE_LIQUIDITY_PROVIDER_ID,
} from 'common/antes' } from 'common/antes'
import { useIsMobile } from 'web/hooks/use-is-mobile' import { useIsMobile } from 'web/hooks/use-is-mobile'
import { formatMoney } from 'common/lib/util/format' import { formatMoney } from 'common/util/format'
import { Button } from 'web/components/button' import { Button } from 'web/components/button'
import { MINUTE_MS } from 'common/lib/util/time' import { MINUTE_MS } from 'common/util/time'
export function ContractTabs(props: { contract: Contract; bets: Bet[] }) { export function ContractTabs(props: { contract: Contract; bets: Bet[] }) {
const { contract, bets } = props const { contract, bets } = props