diff --git a/common/util/format.ts b/common/util/format.ts index 2d8e5d00..4f123535 100644 --- a/common/util/format.ts +++ b/common/util/format.ts @@ -7,13 +7,9 @@ const formatter = new Intl.NumberFormat('en-US', { minimumFractionDigits: 0, }) -export function formatMoney(amount: number, explicitPositiveSign?: boolean) { +export function formatMoney(amount: number) { const newAmount = Math.round(amount) === 0 ? 0 : Math.floor(amount) // handle -0 case - return ( - ENV_CONFIG.moneyMoniker + - (explicitPositiveSign && newAmount > 0 ? '+' : '') + - formatter.format(newAmount).replace('$', '') - ) + return ENV_CONFIG.moneyMoniker + formatter.format(newAmount).replace('$', '') } export function formatMoneyWithDecimals(amount: number) { diff --git a/functions/src/email-templates/weekly-portfolio-update.html b/functions/src/email-templates/weekly-portfolio-update.html index 547a6b3b..b4104205 100644 --- a/functions/src/email-templates/weekly-portfolio-update.html +++ b/functions/src/email-templates/weekly-portfolio-update.html @@ -29,10 +29,10 @@ mso-table-lspace: 0; mso-table-rspace: 0; } - th {color:#000000; font-size:14px;} - th, td {padding: 5px; } + th {color:#000000; font-size:17px;} + th, td {padding: 10px; } td{ font-size: 17px} - th, td { vertical-align: center; text-align: center } + th, td { vertical-align: center; text-align: left } a { vertical-align: center; text-align: left} img { border: 0; @@ -48,13 +48,19 @@ margin: 13px 0; } p.change{ - margin: 0; vertical-align: middle;font-size:16px;display: inline; padding: 2px; border-radius: 5px; + margin: 0; vertical-align: middle;font-size:16px;display: inline; padding: 2px; border-radius: 5px; width: 20px; text-align: right; } p.prob{ - font-size: 20px;display: inline; vertical-align: middle; font-weight: bold; + font-size: 22px;display: inline; vertical-align: middle; font-weight: bold; width: 50px; } a.question{ - font-size: 18px;display: inline; vertical-align: middle; padding-bottom: 25px; + font-size: 18px;display: inline; vertical-align: middle; + } + td.question{ + vertical-align: middle; padding-bottom: 15px; text-align: left; + } + td.probs{ + text-align: right; padding-left: 10px; min-width: 115px } - - - Profit - - - - - {{profit}} - - + + + Profit + + + + +

+ {{profit}} +

+ + + style="border-collapse:collapse;border-spacing:0px; "> - - - - - - + + + + + + + + + + + - - - - + + + + +
- Investment value - - Balance - - Tips - - Markets - - Traders - + 🔥 Prediction streak + + {{prediction_streak}} +
+ 💸 Tips received + + {{tips_received}} +
+ 📈 Markets traded + + {{markets_traded}} +
+ ❓ Markets created + - {{investment_value}} - -

- {{investment_change}} - -

-
- {{current_balance}} - -

- {{tips_received}} -

- -
{{markets_created}} - {{unique_bettors}} -
+ 🥳 Unique traders + + {{unique_bettors}} +
@@ -311,7 +317,7 @@

And here's some of the biggest changes in your portfolio: @@ -325,17 +331,16 @@ - - - - - - - - - -
+ {{question1Title}} +

{{question1Prob}} - +

{{question1Change}} @@ -343,32 +348,31 @@

+ {{question2Title}} - + +

{{question2Prob}}

{{question2Change}} - +

+ {{question3Title}} +

{{question3Prob}} @@ -380,13 +384,13 @@

+ {{question4Title}} +

{{question4Prob}} diff --git a/functions/src/emails.ts b/functions/src/emails.ts index 298e5ef8..1beb8477 100644 --- a/functions/src/emails.ts +++ b/functions/src/emails.ts @@ -16,10 +16,7 @@ import { contractUrl, getUser } from './utils' import { buildCardUrl, getOpenGraphProps } from '../../common/contract-details' import { notification_reason_types } from '../../common/notification' import { Dictionary } from 'lodash' -import { - getNotificationDestinationsForUser, - notification_preference, -} from '../../common/user-notification-preferences' +import { getNotificationDestinationsForUser } from '../../common/user-notification-preferences' import { PerContractInvestmentsData, OverallPerformanceData, @@ -156,9 +153,10 @@ export const sendWelcomeEmail = async ( const { name } = user const firstName = name.split(' ')[0] - const unsubscribeUrl = `${DOMAIN}/notifications?tab=settings§ion=${ - 'onboarding_flow' as notification_preference - }` + const { unsubscribeUrl } = getNotificationDestinationsForUser( + privateUser, + 'onboarding_flow' + ) return await sendTemplateEmail( privateUser.email, @@ -224,9 +222,11 @@ export const sendOneWeekBonusEmail = async ( const { name } = user const firstName = name.split(' ')[0] - const unsubscribeUrl = `${DOMAIN}/notifications?tab=settings§ion=${ - 'onboarding_flow' as notification_preference - }` + const { unsubscribeUrl } = getNotificationDestinationsForUser( + privateUser, + 'onboarding_flow' + ) + return await sendTemplateEmail( privateUser.email, 'Manifold Markets one week anniversary gift', @@ -256,10 +256,10 @@ export const sendCreatorGuideEmail = async ( const { name } = user const firstName = name.split(' ')[0] - - const unsubscribeUrl = `${DOMAIN}/notifications?tab=settings§ion=${ - 'onboarding_flow' as notification_preference - }` + const { unsubscribeUrl } = getNotificationDestinationsForUser( + privateUser, + 'onboarding_flow' + ) return await sendTemplateEmail( privateUser.email, 'Create your own prediction market', @@ -290,10 +290,10 @@ export const sendThankYouEmail = async ( const { name } = user const firstName = name.split(' ')[0] - - const unsubscribeUrl = `${DOMAIN}/notifications?tab=settings§ion=${ - 'thank_you_for_purchases' as notification_preference - }` + const { unsubscribeUrl } = getNotificationDestinationsForUser( + privateUser, + 'thank_you_for_purchases' + ) return await sendTemplateEmail( privateUser.email, @@ -473,9 +473,10 @@ export const sendInterestingMarketsEmail = async ( ) return - const unsubscribeUrl = `${DOMAIN}/notifications?tab=settings§ion=${ - 'trending_markets' as notification_preference - }` + const { unsubscribeUrl } = getNotificationDestinationsForUser( + privateUser, + 'trending_markets' + ) const { name } = user const firstName = name.split(' ')[0] @@ -626,9 +627,10 @@ export const sendWeeklyPortfolioUpdateEmail = async ( ) return - const unsubscribeUrl = `${DOMAIN}/notifications?tab=settings§ion=${ - 'profit_loss_updates' as notification_preference - }` + const { unsubscribeUrl } = getNotificationDestinationsForUser( + privateUser, + 'profit_loss_updates' + ) const { name } = user const firstName = name.split(' ')[0] diff --git a/functions/src/weekly-portfolio-emails.ts b/functions/src/weekly-portfolio-emails.ts index 51a85c9c..e30e8e21 100644 --- a/functions/src/weekly-portfolio-emails.ts +++ b/functions/src/weekly-portfolio-emails.ts @@ -134,6 +134,11 @@ export async function sendPortfolioUpdateEmailsToAllUsers() { const contractsUserBetOn = contractsUsersBetOn.filter((contract) => userBets.some((bet) => bet.contractId === contract.id) ) + const contractsBetOnInLastWeek = uniq( + userBets + .filter((bet) => bet.createdTime > Date.now() - 7 * DAY_MS) + .map((bet) => bet.contractId) + ) // get the most recent bet for each contract // get the most recent portfolio metrics const mostRecentPortfolioMetrics = last( @@ -155,34 +160,27 @@ export async function sendPortfolioUpdateEmailsToAllUsers() { log('No portfolio metrics a week ago for user', privateUser.id) return } - const valueChange = - mostRecentPortfolioMetrics.investmentValue - - portfolioMetricsAWeekAgo.investmentValue const totalTips = sum( usersToTxnsReceived[privateUser.id] .filter((txn) => txn.category === 'TIP') .map((txn) => txn.amount) ) - // get the difference + const greenBg = 'rgba(0,160,0,0.2)' + const redBg = 'rgba(160,0,0,0.2)' const performanceData = { - profit: formatMoney(user.profitCached.weekly, true), - investment_value: formatMoney( - mostRecentPortfolioMetrics.investmentValue - ), - investment_change: formatMoney(valueChange, true), - current_balance: formatMoney(user.balance), + profit: formatMoney(user.profitCached.weekly), + profit_style: `background-color: ${ + user.profitCached.weekly > 0 ? greenBg : redBg + }`, markets_created: usersToContractsCreated[privateUser.id].length.toString(), - tips_received: formatMoney(totalTips, true), - tips_received_style: `background-color: ${ - totalTips > 0 ? 'rgba(0,160,0,0.2)' : 'rgba(160,0,0,0.2)' - };`, + tips_received: formatMoney(totalTips), unique_bettors: usersToTxnsReceived[privateUser.id] .filter((txn) => txn.category === 'UNIQUE_BETTOR_BONUS') .length.toString(), - investment_change_style: `background-color: ${ - valueChange > 0 ? 'rgba(0,160,0,0.2)' : 'rgba(160,0,0,0.2)' - };`, + markets_traded: contractsBetOnInLastWeek.length.toString(), + prediction_streak: + (user.currentBettingStreak?.toString() ?? '0') + ' days', // More options: bonuses, tips given, } as OverallPerformanceData type investmentDiff = { @@ -285,11 +283,9 @@ export type PerContractInvestmentsData = { } export type OverallPerformanceData = { profit: string - tips_received_style: string - investment_change_style: string - investment_value: string - investment_change: string - current_balance: string + prediction_streak: string + markets_traded: string + profit_style: string tips_received: string markets_created: string unique_bettors: string