From c1945b8ae9ff01284db9d9f1e664897c14546f73 Mon Sep 17 00:00:00 2001 From: Ian Philips Date: Fri, 9 Sep 2022 14:34:51 -0600 Subject: [PATCH] Direct & highlight sections for notif mgmt from emails --- common/user.ts | 8 + functions/src/create-notification.ts | 16 +- functions/src/email-templates/500-mana.html | 9 +- .../src/email-templates/creating-market.html | 2 +- .../email-templates/interesting-markets.html | 5 +- .../market-answer-comment.html | 17 +- .../src/email-templates/market-answer.html | 13 +- .../src/email-templates/market-close.html | 13 +- .../src/email-templates/market-comment.html | 13 +- .../src/email-templates/market-resolved.html | 13 +- functions/src/email-templates/one-week.html | 9 +- functions/src/email-templates/thank-you.html | 10 +- functions/src/email-templates/welcome.html | 9 +- functions/src/emails.ts | 122 +++++----- web/components/notification-settings.tsx | 230 +++++++++--------- web/pages/notifications.tsx | 30 ++- 16 files changed, 261 insertions(+), 258 deletions(-) diff --git a/common/user.ts b/common/user.ts index 8622be1e..dbf41c72 100644 --- a/common/user.ts +++ b/common/user.ts @@ -116,6 +116,8 @@ export type notification_subscription_types = { contract_from_followed_user: notification_destination_types[] trending_markets: notification_destination_types[] profit_loss_updates: notification_destination_types[] + onboarding_flow: notification_destination_types[] + thank_you_for_purchases: notification_destination_types[] } export type notification_subscribe_types = 'all' | 'less' | 'none' @@ -143,6 +145,7 @@ export const getDefaultNotificationSettings = ( unsubscribedFromAnswerEmails, unsubscribedFromResolutionEmails, unsubscribedFromWeeklyTrendingEmails, + unsubscribedFromGenericEmails, } = privateUser || {} const constructPref = (browserIf: boolean, emailIf: boolean) => { @@ -258,5 +261,10 @@ export const getDefaultNotificationSettings = ( wantsAll || wantsLess, false ), + thank_you_for_purchases: constructPref( + false, + !unsubscribedFromGenericEmails + ), + onboarding_flow: constructPref(false, !unsubscribedFromGenericEmails), } as notification_subscription_types } diff --git a/functions/src/create-notification.ts b/functions/src/create-notification.ts index 600d6cbb..c7e30483 100644 --- a/functions/src/create-notification.ts +++ b/functions/src/create-notification.ts @@ -23,6 +23,7 @@ import { sendNewAnswerEmail, sendNewCommentEmail, } from './emails' +import { DOMAIN } from 'common/lib/envs/constants' const firestore = admin.firestore() type recipients_to_reason_texts = { @@ -92,7 +93,7 @@ export const createNotification = async ( if (!sendToEmail) continue if (reason === 'your_contract_closed' && privateUser && sourceContract) { - await sendMarketCloseEmail(sourceUser, privateUser, sourceContract) + await sendMarketCloseEmail(reason, sourceUser, sourceContract) } else if (reason === 'tagged_user') { // TODO: send email to tagged user in new contract } else if (reason === 'subsidized_your_market') { @@ -196,7 +197,7 @@ export const createNotification = async ( await sendNotificationsIfSettingsPermit(userToReasonTexts) } -const getDestinationsForUser = async ( +export const getDestinationsForUser = async ( userId: string, reason: notification_reason_types | keyof notification_subscription_types ) => { @@ -206,12 +207,13 @@ const getDestinationsForUser = async ( const notificationSettings = privateUser.notificationSubscriptionTypes let destinations + let subscriptionType: keyof notification_subscription_types | undefined if (Object.keys(notificationSettings).includes(reason)) { - const key = reason as keyof notification_subscription_types - destinations = notificationSettings[key] + subscriptionType = reason as keyof notification_subscription_types + destinations = notificationSettings[subscriptionType] } else { const key = reason as notification_reason_types - const subscriptionType = notificationReasonToSubscriptionType[key] + subscriptionType = notificationReasonToSubscriptionType[key] destinations = subscriptionType ? notificationSettings[subscriptionType] : [] @@ -220,6 +222,7 @@ const getDestinationsForUser = async ( sendToEmail: destinations.includes('email'), sendToBrowser: destinations.includes('browser'), privateUser, + urlToManageThisNotification: `${DOMAIN}/notifications?section=${subscriptionType}`, } } @@ -326,6 +329,7 @@ export const createCommentOrAnswerOrUpdatedContractNotification = async ( if (sourceType === 'comment') { // if the source contract is a free response contract, send the email await sendNewCommentEmail( + reason, userId, sourceUser, sourceContract, @@ -338,6 +342,7 @@ export const createCommentOrAnswerOrUpdatedContractNotification = async ( ) } else if (sourceType === 'answer') await sendNewAnswerEmail( + reason, userId, sourceUser.name, sourceText, @@ -350,6 +355,7 @@ export const createCommentOrAnswerOrUpdatedContractNotification = async ( resolutionData ) await sendMarketResolutionEmail( + reason, userId, resolutionData.userInvestments[userId], resolutionData.userPayouts[userId], diff --git a/functions/src/email-templates/500-mana.html b/functions/src/email-templates/500-mana.html index 6c75f026..8ba5f114 100644 --- a/functions/src/email-templates/500-mana.html +++ b/functions/src/email-templates/500-mana.html @@ -284,9 +284,12 @@ style="font-size:0px;padding:10px 25px;padding-top:0px;padding-bottom:0px;word-break:break-word;">
-

This e-mail has been sent to {{name}}, click here to unsubscribe.

+

This e-mail has been sent to {{name}}, + click here to manage your notifications. +

diff --git a/functions/src/email-templates/creating-market.html b/functions/src/email-templates/creating-market.html index a61e8d65..1b6f1849 100644 --- a/functions/src/email-templates/creating-market.html +++ b/functions/src/email-templates/creating-market.html @@ -493,7 +493,7 @@ click here to unsubscribe. + " target="_blank">click here to manage your notifications.

diff --git a/functions/src/email-templates/interesting-markets.html b/functions/src/email-templates/interesting-markets.html index d00b227e..5418e377 100644 --- a/functions/src/email-templates/interesting-markets.html +++ b/functions/src/email-templates/interesting-markets.html @@ -440,11 +440,10 @@

This e-mail has been sent to {{name}}, - click here to unsubscribe from future recommended markets. + " target="_blank">click here to manage your notifications.

diff --git a/functions/src/email-templates/market-answer-comment.html b/functions/src/email-templates/market-answer-comment.html index 4e1a2bfa..175c465e 100644 --- a/functions/src/email-templates/market-answer-comment.html +++ b/functions/src/email-templates/market-answer-comment.html @@ -526,19 +526,10 @@ " >our Discord! Or, - unsubscribe. + click here to manage your notifications. diff --git a/functions/src/email-templates/market-answer.html b/functions/src/email-templates/market-answer.html index 1f7fa5fa..96a11771 100644 --- a/functions/src/email-templates/market-answer.html +++ b/functions/src/email-templates/market-answer.html @@ -366,15 +366,10 @@ text-decoration: underline; margin: 0; ">our Discord! Or, - unsubscribe. + click here to manage your notifications. diff --git a/functions/src/email-templates/market-close.html b/functions/src/email-templates/market-close.html index fa44c1d5..45a888ac 100644 --- a/functions/src/email-templates/market-close.html +++ b/functions/src/email-templates/market-close.html @@ -484,15 +484,10 @@ text-decoration: underline; margin: 0; ">our Discord! Or, - unsubscribe. + click here to manage your notifications. diff --git a/functions/src/email-templates/market-comment.html b/functions/src/email-templates/market-comment.html index 0b5b9a54..73849989 100644 --- a/functions/src/email-templates/market-comment.html +++ b/functions/src/email-templates/market-comment.html @@ -366,15 +366,10 @@ text-decoration: underline; margin: 0; ">our Discord! Or, - unsubscribe. + click here to manage your notifications. diff --git a/functions/src/email-templates/market-resolved.html b/functions/src/email-templates/market-resolved.html index c1ff3beb..b9d215fa 100644 --- a/functions/src/email-templates/market-resolved.html +++ b/functions/src/email-templates/market-resolved.html @@ -499,15 +499,10 @@ text-decoration: underline; margin: 0; ">our Discord! Or, - unsubscribe. + click here to manage your notifications. diff --git a/functions/src/email-templates/one-week.html b/functions/src/email-templates/one-week.html index 94889772..5e160854 100644 --- a/functions/src/email-templates/one-week.html +++ b/functions/src/email-templates/one-week.html @@ -487,15 +487,10 @@ >

This e-mail has been sent to {{name}}, - click here to unsubscribe. + " target="_blank">click here to manage your notifications.

diff --git a/functions/src/email-templates/thank-you.html b/functions/src/email-templates/thank-you.html index c4ad7baa..78a7af26 100644 --- a/functions/src/email-templates/thank-you.html +++ b/functions/src/email-templates/thank-you.html @@ -214,10 +214,12 @@

This e-mail has been sent - to {{name}}, click here to - unsubscribe.

+ to {{name}}, + click here to manage your notifications. +

diff --git a/functions/src/email-templates/welcome.html b/functions/src/email-templates/welcome.html index 366709e3..49c42112 100644 --- a/functions/src/email-templates/welcome.html +++ b/functions/src/email-templates/welcome.html @@ -286,9 +286,12 @@ style="font-size:0px;padding:10px 25px;padding-top:0px;padding-bottom:0px;word-break:break-word;">
-

This e-mail has been sent to {{name}}, click here to unsubscribe.

+

This e-mail has been sent to {{name}}, + click here to manage your notifications. +

diff --git a/functions/src/emails.ts b/functions/src/emails.ts index 44d3d7ee..3d780b25 100644 --- a/functions/src/emails.ts +++ b/functions/src/emails.ts @@ -2,7 +2,11 @@ import { DOMAIN } from '../../common/envs/constants' import { Bet } from '../../common/bet' import { getProbability } from '../../common/calculate' import { Contract } from '../../common/contract' -import { PrivateUser, User } from '../../common/user' +import { + notification_subscription_types, + PrivateUser, + User, +} from '../../common/user' import { formatLargeNumber, formatMoney, @@ -12,13 +16,13 @@ import { getValueFromBucket } from '../../common/calculate-dpm' import { formatNumericProbability } from '../../common/pseudo-numeric' import { sendTemplateEmail, sendTextEmail } from './send-email' -import { getPrivateUser, getUser } from './utils' -import { getFunctionUrl } from '../../common/api' +import { getUser } from './utils' import { buildCardUrl, getOpenGraphProps } from '../../common/contract-details' - -const UNSUBSCRIBE_ENDPOINT = getFunctionUrl('unsubscribe') +import { notification_reason_types } from '../../common/notification' +import { getDestinationsForUser } from './create-notification' export const sendMarketResolutionEmail = async ( + reason: notification_reason_types, userId: string, investment: number, payout: number, @@ -29,13 +33,12 @@ export const sendMarketResolutionEmail = async ( resolutionProbability?: number, resolutions?: { [outcome: string]: number } ) => { - const privateUser = await getPrivateUser(userId) - if ( - !privateUser || - privateUser.unsubscribedFromResolutionEmails || - !privateUser.email - ) - return + const { + privateUser, + sendToEmail, + urlToManageThisNotification: unsubscribeUrl, + } = await getDestinationsForUser(userId, reason) + if (!privateUser || !privateUser.email || !sendToEmail) return const user = await getUser(userId) if (!user) return @@ -54,9 +57,6 @@ export const sendMarketResolutionEmail = async ( ? ` (plus ${formatMoney(creatorPayout)} in commissions)` : '' - const emailType = 'market-resolved' - const unsubscribeUrl = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}` - const displayedInvestment = Number.isNaN(investment) || investment < 0 ? formatMoney(0) @@ -151,11 +151,12 @@ export const sendWelcomeEmail = async ( ) => { if (!privateUser || !privateUser.email) return - const { name, id: userId } = user + const { name } = user const firstName = name.split(' ')[0] - const emailType = 'generic' - const unsubscribeLink = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}` + const unsubscribeLink = `${DOMAIN}/notifications?section=${ + 'onboarding_flow' as keyof notification_subscription_types + }` return await sendTemplateEmail( privateUser.email, @@ -214,16 +215,16 @@ export const sendOneWeekBonusEmail = async ( if ( !privateUser || !privateUser.email || - privateUser.unsubscribedFromGenericEmails + !privateUser.notificationSubscriptionTypes.onboarding_flow.includes('email') ) return const { name, id: userId } = user const firstName = name.split(' ')[0] - const emailType = 'generic' - const unsubscribeLink = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}` - + const unsubscribeLink = `${DOMAIN}/notifications?section=${ + 'onboarding_flow' as keyof notification_subscription_types + }` return await sendTemplateEmail( privateUser.email, 'Manifold Markets one week anniversary gift', @@ -247,16 +248,16 @@ export const sendCreatorGuideEmail = async ( if ( !privateUser || !privateUser.email || - privateUser.unsubscribedFromGenericEmails + !privateUser.notificationSubscriptionTypes.onboarding_flow.includes('email') ) return const { name, id: userId } = user const firstName = name.split(' ')[0] - const emailType = 'generic' - const unsubscribeLink = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}` - + const unsubscribeLink = `${DOMAIN}/notifications?section=${ + 'onboarding_flow' as keyof notification_subscription_types + }` return await sendTemplateEmail( privateUser.email, 'Create your own prediction market', @@ -279,15 +280,18 @@ export const sendThankYouEmail = async ( if ( !privateUser || !privateUser.email || - privateUser.unsubscribedFromGenericEmails + !privateUser.notificationSubscriptionTypes.thank_you_for_purchases.includes( + 'email' + ) ) return - const { name, id: userId } = user + const { name } = user const firstName = name.split(' ')[0] - const emailType = 'generic' - const unsubscribeLink = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}` + const unsubscribeLink = `${DOMAIN}/notifications?section=${ + 'thank_you_for_purchases' as keyof notification_subscription_types + }` return await sendTemplateEmail( privateUser.email, @@ -304,16 +308,17 @@ export const sendThankYouEmail = async ( } export const sendMarketCloseEmail = async ( + reason: notification_reason_types, user: User, - privateUser: PrivateUser, contract: Contract ) => { - if ( - !privateUser || - privateUser.unsubscribedFromResolutionEmails || - !privateUser.email - ) - return + const { + privateUser, + sendToEmail, + urlToManageThisNotification: unsubscribeUrl, + } = await getDestinationsForUser(user.id, reason) + + if (!privateUser || !privateUser.email || !sendToEmail) return const { username, name, id: userId } = user const firstName = name.split(' ')[0] @@ -321,8 +326,6 @@ export const sendMarketCloseEmail = async ( const { question, slug, volume } = contract const url = `https://${DOMAIN}/${username}/${slug}` - const emailType = 'market-resolve' - const unsubscribeUrl = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}` return await sendTemplateEmail( privateUser.email, @@ -340,6 +343,7 @@ export const sendMarketCloseEmail = async ( } export const sendNewCommentEmail = async ( + reason: notification_reason_types, userId: string, commentCreator: User, contract: Contract, @@ -349,18 +353,15 @@ export const sendNewCommentEmail = async ( answerText?: string, answerId?: string ) => { - const privateUser = await getPrivateUser(userId) - if ( - !privateUser || - !privateUser.email || - privateUser.unsubscribedFromCommentEmails - ) - return + const { + privateUser, + sendToEmail, + urlToManageThisNotification: unsubscribeUrl, + } = await getDestinationsForUser(userId, reason) + if (!privateUser || !privateUser.email || !sendToEmail) return const { question } = contract const marketUrl = `https://${DOMAIN}/${contract.creatorUsername}/${contract.slug}#${commentId}` - const emailType = 'market-comment' - const unsubscribeUrl = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}` const { name: commentorName, avatarUrl: commentorAvatarUrl } = commentCreator @@ -419,6 +420,7 @@ export const sendNewCommentEmail = async ( } export const sendNewAnswerEmail = async ( + reason: notification_reason_types, userId: string, name: string, text: string, @@ -429,19 +431,16 @@ export const sendNewAnswerEmail = async ( // Don't send the creator's own answers. if (userId === creatorId) return - const privateUser = await getPrivateUser(userId) - if ( - !privateUser || - !privateUser.email || - privateUser.unsubscribedFromAnswerEmails - ) - return + const { + privateUser, + sendToEmail, + urlToManageThisNotification: unsubscribeUrl, + } = await getDestinationsForUser(userId, reason) + if (!privateUser || !privateUser.email || !sendToEmail) return const { question, creatorUsername, slug } = contract const marketUrl = `https://${DOMAIN}/${creatorUsername}/${slug}` - const emailType = 'market-answer' - const unsubscribeUrl = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}` const subject = `New answer on ${question}` const from = `${name} ` @@ -470,12 +469,15 @@ export const sendInterestingMarketsEmail = async ( if ( !privateUser || !privateUser.email || - privateUser?.unsubscribedFromWeeklyTrendingEmails + !privateUser.notificationSubscriptionTypes.trending_markets.includes( + 'email' + ) ) return - const emailType = 'weekly-trending' - const unsubscribeUrl = `${UNSUBSCRIBE_ENDPOINT}?id=${privateUser.id}&type=${emailType}` + const unsubscribeUrl = `${DOMAIN}/notifications?section=${ + 'trending_markets' as keyof notification_subscription_types + }` const { name } = user const firstName = name.split(' ')[0] diff --git a/web/components/notification-settings.tsx b/web/components/notification-settings.tsx index 056f2ca1..551e4d73 100644 --- a/web/components/notification-settings.tsx +++ b/web/components/notification-settings.tsx @@ -27,7 +27,10 @@ import { WatchMarketModal } from 'web/components/contract/watch-market-modal' import { filterDefined } from 'common/util/array' import toast from 'react-hot-toast' -export function NotificationSettings() { +export function NotificationSettings(props: { + navigateToSection: string | undefined +}) { + const { navigateToSection } = props const privateUser = usePrivateUser() const [showWatchModal, setShowWatchModal] = useState(false) @@ -53,6 +56,8 @@ export function NotificationSettings() { 'tagged_user', 'trending_markets', + 'onboarding_flow', + 'thank_you_for_purchases', // TODO: add these // 'contract_from_followed_user', @@ -67,77 +72,94 @@ export function NotificationSettings() { // 'probability_updates_on_watched_markets', // 'limit_order_fills', ] - const browserDisabled = ['trending_markets', 'profit_loss_updates'] + const browserDisabled: Array = [ + 'trending_markets', + 'profit_loss_updates', + 'onboarding_flow', + 'thank_you_for_purchases', + ] - const watched_markets_explanations_comments: { - [key in keyof Partial]: string - } = { - all_comments_on_watched_markets: 'All', - all_replies_to_my_comments_on_watched_markets: 'Replies to your comments', - all_comments_on_contracts_with_shares_in_on_watched_markets: - 'On markets you have shares in', - // comments_by_followed_users_on_watched_markets: 'By followed users', - } - const watched_markets_explanations_answers: { - [key in keyof Partial]: string - } = { - all_answers_on_watched_markets: 'All', - all_replies_to_my_answers_on_watched_markets: 'Replies to your answers', - all_answers_on_contracts_with_shares_in_on_watched_markets: - 'On markets you have shares in', - // answers_by_followed_users_on_watched_markets: 'By followed users', - // answers_by_market_creator_on_watched_markets: 'By market creator', - } - const watched_markets_explanations_your_markets: { - [key in keyof Partial]: string - } = { - your_contract_closed: 'Your market has closed (and needs resolution)', - all_comments_on_my_markets: 'Comments on your markets', - all_answers_on_my_markets: 'Answers on your markets', - subsidized_your_market: 'Your market was subsidized', - tips_on_your_markets: 'Likes on your markets', - } - const watched_markets_explanations_market_updates: { - [key in keyof Partial]: string - } = { - market_updates_on_watched_markets: 'Updates made by the creator', - market_updates_on_watched_markets_with_shares_in: - 'Updates made by the creator on markets you have shares in', - resolutions_on_watched_markets: 'Market resolutions', - resolutions_on_watched_markets_with_shares_in: - 'Market resolutions you have shares in', - // probability_updates_on_watched_markets: 'Probability updates', + type sectionData = { + label: string + subscriptionTypeToDescription: { + [key in keyof Partial]: string + } } - const bonuses_explanations: { - [key in keyof Partial]: string - } = { - betting_streaks: 'Betting streak bonuses', - referral_bonuses: 'Referral bonuses from referring users', - unique_bettors_on_your_contract: 'Unique bettor bonuses on your markets', + const comments: sectionData = { + label: 'New Comments', + subscriptionTypeToDescription: { + all_comments_on_watched_markets: 'All new comments', + all_comments_on_contracts_with_shares_in_on_watched_markets: `Only on markets you're invested in`, + all_replies_to_my_comments_on_watched_markets: + 'Only replies to your comments', + // comments_by_followed_users_on_watched_markets: 'By followed users', + }, } - const other_balance_change_explanations: { - [key in keyof Partial]: string - } = { - loan_income: 'Automatic loans from your profitable bets', - limit_order_fills: 'Limit order fills', - tips_on_your_comments: 'Tips on your comments', + const answers: sectionData = { + label: 'New Answers', + subscriptionTypeToDescription: { + all_answers_on_watched_markets: 'All new answers', + all_answers_on_contracts_with_shares_in_on_watched_markets: `Only on markets you're invested in`, + all_replies_to_my_answers_on_watched_markets: + 'Only replies to your answers', + // answers_by_followed_users_on_watched_markets: 'By followed users', + // answers_by_market_creator_on_watched_markets: 'By market creator', + }, } - - const general_explanations: { - [key in keyof Partial]: string - } = { - tagged_user: 'A user tagged you', - trending_markets: 'Weekly trending markets', - // profit_loss_updates: 'Weekly profit/loss updates', + const updates: sectionData = { + label: 'Updates & Resolutions', + subscriptionTypeToDescription: { + market_updates_on_watched_markets: 'All creator updates', + market_updates_on_watched_markets_with_shares_in: `Only creator updates on markets you're invested in`, + resolutions_on_watched_markets: 'All market resolutions', + resolutions_on_watched_markets_with_shares_in: `Only market resolutions you're invested in`, + // probability_updates_on_watched_markets: 'Probability updates', + }, } - - const follows_and_followers_explanations: { - [key in keyof Partial]: string - } = { - on_new_follow: 'New followers', - contract_from_followed_user: 'New markets created by users you follow', + const yourMarkets: sectionData = { + label: 'Markets You Created', + subscriptionTypeToDescription: { + your_contract_closed: 'Your market has closed (and needs resolution)', + all_comments_on_my_markets: 'Comments on your markets', + all_answers_on_my_markets: 'Answers on your markets', + subsidized_your_market: 'Your market was subsidized', + tips_on_your_markets: 'Likes on your markets', + }, + } + const bonuses: sectionData = { + label: 'Bonuses', + subscriptionTypeToDescription: { + betting_streaks: 'Betting streak bonuses', + referral_bonuses: 'Referral bonuses from referring users', + unique_bettors_on_your_contract: 'Unique bettor bonuses on your markets', + }, + } + const otherBalances: sectionData = { + label: 'Other', + subscriptionTypeToDescription: { + loan_income: 'Automatic loans from your profitable bets', + limit_order_fills: 'Limit order fills', + tips_on_your_comments: 'Tips on your comments', + }, + } + const userInteractions: sectionData = { + label: 'Users', + subscriptionTypeToDescription: { + tagged_user: 'A user tagged you', + on_new_follow: 'Someone followed you', + contract_from_followed_user: 'New markets created by users you follow', + }, + } + const generalOther: sectionData = { + label: 'Other', + subscriptionTypeToDescription: { + trending_markets: 'Weekly interesting markets', + thank_you_for_purchases: 'Thank you notes for your purchases', + onboarding_flow: 'Explanatory emails to help you get started', + // profit_loss_updates: 'Weekly profit/loss updates', + }, } const NotificationSettingLine = ( @@ -151,6 +173,7 @@ export function NotificationSettings() { const [emailEnabled, setEmailEnabled] = useState(previousEmailValue) const loading = 'Changing Notifications Settings' const success = 'Changed Notification Settings!' + const highlight = navigateToSection === key useEffect(() => { if ( @@ -183,7 +206,12 @@ export function NotificationSettings() { ]) return ( - + {description} @@ -251,16 +279,20 @@ export function NotificationSettings() { return privateUser.notificationSubscriptionTypes[key] ?? [] } - const Section = ( - icon: ReactNode, - label: string, - subscriptionTypeToDescription: { - [key in keyof Partial]: string - } - ) => { - const [expanded, setExpanded] = useState(false) + const Section = (icon: ReactNode, data: sectionData) => { + const { label, subscriptionTypeToDescription } = data + const expand = + navigateToSection && + Object.keys(subscriptionTypeToDescription).includes(navigateToSection) + const [expanded, setExpanded] = useState(expand) + + // Not working as the default value for expanded, so using a useEffect + useEffect(() => { + if (expand) setExpanded(true) + }, [expand]) + return ( - + setExpanded(!expanded)} @@ -303,52 +335,20 @@ export function NotificationSettings() { onClick={() => setShowWatchModal(true)} /> - {Section( - , - 'New Comments', - watched_markets_explanations_comments - )} - {Section( - , - 'New Answers', - watched_markets_explanations_answers - )} - {Section( - , - 'Updates & Resolutions', - watched_markets_explanations_market_updates - )} - {Section( - , - 'Markets You Created', - watched_markets_explanations_your_markets - )} + {Section(, comments)} + {Section(, answers)} + {Section(, updates)} + {Section(, yourMarkets)} Balance Changes - {Section( - , - 'Bonuses', - bonuses_explanations - )} - {Section( - , - 'Other', - other_balance_change_explanations - )} + {Section(, bonuses)} + {Section(, otherBalances)} General - {Section( - , - 'Follows & Followers', - follows_and_followers_explanations - )} - {Section( - , - 'Other', - general_explanations - )} + {Section(, userInteractions)} + {Section(, generalOther)} diff --git a/web/pages/notifications.tsx b/web/pages/notifications.tsx index 897e3ca6..6f95818e 100644 --- a/web/pages/notifications.tsx +++ b/web/pages/notifications.tsx @@ -1,6 +1,6 @@ -import { Tabs } from 'web/components/layout/tabs' +import { ControlledTabs } from 'web/components/layout/tabs' import React, { useEffect, useMemo, useState } from 'react' -import Router from 'next/router' +import Router, { useRouter } from 'next/router' import { Notification, notification_source_types } from 'common/notification' import { Avatar, EmptyAvatar } from 'web/components/avatar' import { Row } from 'web/components/layout/row' @@ -56,24 +56,38 @@ const HIGHLIGHT_CLASS = 'bg-indigo-50' export default function Notifications() { const privateUser = usePrivateUser() + const router = useRouter() + const [navigateToSection, setNavigateToSection] = useState() + const [activeIndex, setActiveIndex] = useState(0) useEffect(() => { if (privateUser === null) Router.push('/') }) + useEffect(() => { + const query = { ...router.query } + if (query.section) { + setNavigateToSection(query.section as string) + setActiveIndex(1) + } + }, [router.query]) + return (
<SEO title="Notifications" description="Manifold user notifications" /> - {privateUser && ( + {privateUser && router.isReady && ( <div> - <Tabs + <ControlledTabs currentPageForAnalytics={'notifications'} labelClassName={'pb-2 pt-1 '} className={'mb-0 sm:mb-2'} - defaultIndex={0} + activeIndex={activeIndex} + onClick={(title, index) => { + setActiveIndex(index) + }} tabs={[ { title: 'Notifications', @@ -82,9 +96,9 @@ export default function Notifications() { { title: 'Settings', content: ( - <div className={''}> - <NotificationSettings /> - </div> + <NotificationSettings + navigateToSection={navigateToSection} + /> ), }, ]}