From 91fd2d8a2d9b84006768143f80ea81a9cfd51146 Mon Sep 17 00:00:00 2001 From: James Grugett Date: Fri, 19 Aug 2022 11:01:28 -0500 Subject: [PATCH] Implement loan income notification --- common/notification.ts | 2 ++ functions/src/create-notification.ts | 20 ++++++++++++++++++++ functions/src/update-loans.ts | 17 +++++++++++++---- web/hooks/use-notifications.ts | 13 ++++++------- web/pages/notifications.tsx | 2 ++ 5 files changed, 43 insertions(+), 11 deletions(-) diff --git a/common/notification.ts b/common/notification.ts index fa4cd90a..8ced082a 100644 --- a/common/notification.ts +++ b/common/notification.ts @@ -38,6 +38,7 @@ export type notification_source_types = | 'user' | 'bonus' | 'challenge' + | 'loan' export type notification_source_update_types = | 'created' @@ -66,3 +67,4 @@ export type notification_reason_types = | 'bet_fill' | 'user_joined_from_your_group_invite' | 'challenge_accepted' + | 'loan_income' diff --git a/functions/src/create-notification.ts b/functions/src/create-notification.ts index 51b884ad..39376f61 100644 --- a/functions/src/create-notification.ts +++ b/functions/src/create-notification.ts @@ -18,6 +18,7 @@ import { TipTxn } from '../../common/txn' import { Group, GROUP_CHAT_SLUG } from '../../common/group' import { Challenge } from '../../common/challenge' import { richTextToString } from '../../common/util/parse' +import { formatMoney } from 'common/util/format' const firestore = admin.firestore() type user_to_reason_texts = { @@ -471,6 +472,25 @@ export const createReferralNotification = async ( await notificationRef.set(removeUndefinedProps(notification)) } +export const createLoanIncomeNotification = async ( + toUser: User, + idempotencyKey: string, + income: number +) => { + const notificationRef = firestore + .collection(`/users/${toUser.id}/notifications`) + .doc(idempotencyKey) + const notification: Notification = { + id: idempotencyKey, + userId: toUser.id, + reason: 'loan_income', + createdTime: Date.now(), + isSeen: false, + sourceText: formatMoney(income), + } + await notificationRef.set(removeUndefinedProps(notification)) +} + const groupPath = (groupSlug: string) => `/group/${groupSlug}` export const createChallengeAcceptedNotification = async ( diff --git a/functions/src/update-loans.ts b/functions/src/update-loans.ts index 19517de1..48544303 100644 --- a/functions/src/update-loans.ts +++ b/functions/src/update-loans.ts @@ -7,6 +7,7 @@ import { PortfolioMetrics, User } from 'common/user' import { Dictionary, groupBy, keyBy, minBy, sumBy } from 'lodash' import { filterDefined } from 'common/util/array' import { getContractBetMetrics } from 'common/calculate' +import { createLoanIncomeNotification } from './create-notification' const firestore = admin.firestore() @@ -68,14 +69,22 @@ async function updateLoansCore() { (update) => update.userId === user.id ) return { - userId: user.id, - delta: sumBy(updates, (update) => update.newLoan), + user, + payout: sumBy(updates, (update) => update.newLoan), } }) - .filter((update) => update.delta > 0) + .filter((update) => update.payout > 0) await Promise.all( - userPayouts.map(({ userId, delta }) => payUser(userId, delta)) + userPayouts.map(({ user, payout }) => payUser(user.id, payout)) + ) + + const today = new Date().toDateString().replace(' ', '_') + const key = `loan-notifications/${today}` + await Promise.all( + userPayouts.map(({ user, payout }) => + createLoanIncomeNotification(user, key, payout) + ) ) } diff --git a/web/hooks/use-notifications.ts b/web/hooks/use-notifications.ts index a3ddeb29..989476f4 100644 --- a/web/hooks/use-notifications.ts +++ b/web/hooks/use-notifications.ts @@ -5,7 +5,7 @@ import { getNotificationsQuery, listenForNotifications, } from 'web/lib/firebase/notifications' -import { groupBy, map } from 'lodash' +import { groupBy, map, partition } from 'lodash' import { useFirestoreQueryData } from '@react-query-firebase/firestore' import { NOTIFICATIONS_PER_PAGE } from 'web/pages/notifications' @@ -67,15 +67,14 @@ export function groupNotifications(notifications: Notification[]) { const notificationGroupsByDay = groupBy(notifications, (notification) => new Date(notification.createdTime).toDateString() ) + const incomeSourceTypes = ['bonus', 'tip', 'loan'] + Object.keys(notificationGroupsByDay).forEach((day) => { const notificationsGroupedByDay = notificationGroupsByDay[day] - const incomeNotifications = notificationsGroupedByDay.filter( + const [incomeNotifications, normalNotificationsGroupedByDay] = partition( + notificationsGroupedByDay, (notification) => - notification.sourceType === 'bonus' || notification.sourceType === 'tip' - ) - const normalNotificationsGroupedByDay = notificationsGroupedByDay.filter( - (notification) => - notification.sourceType !== 'bonus' && notification.sourceType !== 'tip' + incomeSourceTypes.includes(notification.sourceType ?? '') ) if (incomeNotifications.length > 0) { notificationGroups = notificationGroups.concat({ diff --git a/web/pages/notifications.tsx b/web/pages/notifications.tsx index 7d06c481..10929113 100644 --- a/web/pages/notifications.tsx +++ b/web/pages/notifications.tsx @@ -966,6 +966,8 @@ function getReasonForShowingNotification( case 'challenge': reasonText = 'accepted your challenge' break + case 'loan': + reasonText = 'got a portion of your bet back' default: reasonText = '' }