Simple bet fill notification

This commit is contained in:
James Grugett 2022-07-10 12:21:42 -05:00
parent e2e59b5726
commit 9e7b3c0887
4 changed files with 101 additions and 3 deletions

View File

@ -62,3 +62,4 @@ export type notification_reason_types =
| 'unique_bettors_on_your_contract'
| 'on_group_you_are_member_of'
| 'tip_received'
| 'bet_fill'

View File

@ -10,7 +10,7 @@ import { Contract } from '../../common/contract'
import { getUserByUsername, getValues } from './utils'
import { Comment } from '../../common/comment'
import { uniq } from 'lodash'
import { Bet } from '../../common/bet'
import { Bet, LimitBet } from '../../common/bet'
import { Answer } from '../../common/answer'
import { getContractBetMetrics } from '../../common/calculate'
import { removeUndefinedProps } from '../../common/util/object'
@ -382,3 +382,37 @@ export const createTipNotification = async (
}
return await notificationRef.set(removeUndefinedProps(notification))
}
export const createBetFillNotification = async (
fromUser: User,
toUser: User,
bet: Bet,
userBet: LimitBet,
contract: Contract,
idempotencyKey: string
) => {
const fill = userBet.fills.find((fill) => fill.matchedBetId === bet.id)
const fillAmount = fill?.amount ?? 0
const notificationRef = firestore
.collection(`/users/${toUser.id}/notifications`)
.doc(idempotencyKey)
const notification: Notification = {
id: idempotencyKey,
userId: toUser.id,
reason: 'bet_fill',
createdTime: Date.now(),
isSeen: false,
sourceId: userBet.id,
sourceType: 'bet',
sourceUpdateType: 'updated',
sourceUserName: fromUser.name,
sourceUserUsername: fromUser.username,
sourceUserAvatarUrl: fromUser.avatarUrl,
sourceText: fillAmount.toString(),
sourceContractCreatorUsername: contract.creatorUsername,
sourceContractTitle: contract.question,
sourceContractSlug: contract.slug,
}
return await notificationRef.set(removeUndefinedProps(notification))
}

View File

@ -1,7 +1,11 @@
import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'
import { keyBy } from 'lodash'
import { Bet } from '../../common/bet'
import { Bet, LimitBet } from '../../common/bet'
import { getContract, getUser, getValues } from './utils'
import { createBetFillNotification } from './create-notification'
import { filterDefined } from '../../common/util/array'
const firestore = admin.firestore()
@ -11,6 +15,8 @@ export const onCreateBet = functions.firestore
const { contractId } = context.params as {
contractId: string
}
const { eventId } = context
const bet = change.data() as Bet
const lastBetTime = bet.createdTime
@ -18,4 +24,47 @@ export const onCreateBet = functions.firestore
.collection('contracts')
.doc(contractId)
.update({ lastBetTime, lastUpdatedTime: Date.now() })
await notifyFills(bet, contractId, eventId)
})
const notifyFills = async (bet: Bet, contractId: string, eventId: string) => {
if (!bet.fills) return
const user = await getUser(bet.userId)
if (!user) return
const contract = await getContract(contractId)
if (!contract) return
const matchedFills = bet.fills.filter((fill) => fill.matchedBetId !== null)
const matchedBets = (
await Promise.all(
matchedFills.map((fill) =>
getValues<LimitBet>(
firestore.collectionGroup('bets').where('id', '==', fill.matchedBetId)
)
)
)
).flat()
const betUsers = await Promise.all(
matchedBets.map((bet) => getUser(bet.userId))
)
const betUsersById = keyBy(filterDefined(betUsers), 'id')
await Promise.all(
matchedBets.map((matchedBet) => {
const matchedUser = betUsersById[matchedBet.userId]
if (!matchedUser) return
return createBetFillNotification(
user,
matchedUser,
bet,
matchedBet,
contract,
eventId
)
})
)
}

View File

@ -795,6 +795,8 @@ function getSourceIdForLinkComponent(
return sourceId
case 'contract':
return ''
case 'bet':
return ''
default:
return sourceId
}
@ -861,8 +863,17 @@ function NotificationTextLabel(props: {
{'+' + formatMoney(parseInt(sourceText))}
</span>
)
} else if (sourceType === 'bet' && sourceText) {
return (
<>
Filled{' '}
<span className="text-primary">
{formatMoney(parseInt(sourceText))}
</span>{' '}
<span>of your limit bet</span>
</>
)
}
// return default text
return (
<div className={className ? className : 'line-clamp-4 whitespace-pre-line'}>
<Linkify text={defaultText} />
@ -913,6 +924,9 @@ function getReasonForShowingNotification(
else if (sourceSlug) reasonText = 'joined because you shared'
else reasonText = 'joined because of you'
break
case 'bet':
reasonText = 'bet against you'
break
default:
reasonText = ''
}