Direct & highlight sections for notif mgmt from emails

This commit is contained in:
Ian Philips 2022-09-09 14:34:51 -06:00
parent 4c4fe665ae
commit c1945b8ae9
16 changed files with 261 additions and 258 deletions

View File

@ -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
}

View File

@ -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],

View File

@ -284,9 +284,12 @@
style="font-size:0px;padding:10px 25px;padding-top:0px;padding-bottom:0px;word-break:break-word;">
<div
style="font-family:Arial, sans-serif;font-size:11px;letter-spacing:normal;line-height:22px;text-align:center;color:#000000;">
<p style="margin: 10px 0;">This e-mail has been sent to {{name}}, <a
href="{{unsubscribeLink}}” style=" color:inherit;text-decoration:none;"
target="_blank">click here to unsubscribe</a>.</p>
<p style="margin: 10px 0;">This e-mail has been sent to {{name}},
<a href="{{unsubscribeLink}}" style="
color: inherit;
text-decoration: none;
" target="_blank">click here to manage your notifications</a>.
</p>
</div>
</td>
</tr>

View File

@ -493,7 +493,7 @@
<a href="{{unsubscribeLink}}" style="
color: inherit;
text-decoration: none;
" target="_blank">click here to unsubscribe</a>.
" target="_blank">click here to manage your notifications</a>.
</p>
</div>
</td>

View File

@ -440,11 +440,10 @@
<p style="margin: 10px 0">
This e-mail has been sent to
{{name}},
<a href="{{unsubscribeLink}}"
style="
<a href="{{unsubscribeLink}}" style="
color: inherit;
text-decoration: none;
" target="_blank">click here to unsubscribe</a> from future recommended markets.
" target="_blank">click here to manage your notifications</a>.
</p>
</div>
</td>

View File

@ -526,19 +526,10 @@
"
>our Discord</a
>! Or,
<a
href="{{unsubscribeUrl}}"
style="
font-family: 'Helvetica Neue', Helvetica, Arial,
sans-serif;
box-sizing: border-box;
font-size: 12px;
color: #999;
text-decoration: underline;
margin: 0;
"
>unsubscribe</a
>.
<a href="{{unsubscribeLink}}" style="
color: inherit;
text-decoration: none;
" target="_blank">click here to manage your notifications</a>.
</td>
</tr>
</table>

View File

@ -366,15 +366,10 @@
text-decoration: underline;
margin: 0;
">our Discord</a>! Or,
<a href="{{unsubscribeUrl}}" style="
font-family: 'Helvetica Neue', Helvetica, Arial,
sans-serif;
box-sizing: border-box;
font-size: 12px;
color: #999;
text-decoration: underline;
margin: 0;
">unsubscribe</a>.
<a href="{{unsubscribeLink}}" style="
color: inherit;
text-decoration: none;
" target="_blank">click here to manage your notifications</a>.
</td>
</tr>
</table>

View File

@ -484,15 +484,10 @@
text-decoration: underline;
margin: 0;
">our Discord</a>! Or,
<a href="{{unsubscribeUrl}}" style="
font-family: 'Helvetica Neue', Helvetica, Arial,
sans-serif;
box-sizing: border-box;
font-size: 12px;
color: #999;
text-decoration: underline;
margin: 0;
">unsubscribe</a>.
<a href="{{unsubscribeLink}}" style="
color: inherit;
text-decoration: none;
" target="_blank">click here to manage your notifications</a>.
</td>
</tr>
</table>

View File

@ -366,15 +366,10 @@
text-decoration: underline;
margin: 0;
">our Discord</a>! Or,
<a href="{{unsubscribeUrl}}" style="
font-family: 'Helvetica Neue', Helvetica, Arial,
sans-serif;
box-sizing: border-box;
font-size: 12px;
color: #999;
text-decoration: underline;
margin: 0;
">unsubscribe</a>.
<a href="{{unsubscribeLink}}" style="
color: inherit;
text-decoration: none;
" target="_blank">click here to manage your notifications</a>.
</td>
</tr>
</table>

View File

@ -499,15 +499,10 @@
text-decoration: underline;
margin: 0;
">our Discord</a>! Or,
<a href="{{unsubscribeUrl}}" style="
font-family: 'Helvetica Neue', Helvetica, Arial,
sans-serif;
box-sizing: border-box;
font-size: 12px;
color: #999;
text-decoration: underline;
margin: 0;
">unsubscribe</a>.
<a href="{{unsubscribeLink}}" style="
color: inherit;
text-decoration: none;
" target="_blank">click here to manage your notifications</a>.
</td>
</tr>
</table>

View File

@ -487,15 +487,10 @@
>
<p style="margin: 10px 0">
This e-mail has been sent to {{name}},
<a
href="{{unsubscribeLink}}"
style="
<a href="{{unsubscribeLink}}" style="
color: inherit;
text-decoration: none;
"
target="_blank"
>click here to unsubscribe</a
>.
" target="_blank">click here to manage your notifications</a>.
</p>
</div>
</td>

View File

@ -214,10 +214,12 @@
<div
style="font-family:Arial, sans-serif;font-size:11px;letter-spacing:normal;line-height:22px;text-align:center;color:#000000;">
<p style="margin: 10px 0;">This e-mail has been sent
to {{name}}, <a href="{{unsubscribeLink}}"
style="color:inherit;text-decoration:none;"
target="_blank">click here to
unsubscribe</a>.</p>
to {{name}},
<a href="{{unsubscribeLink}}" style="
color: inherit;
text-decoration: none;
" target="_blank">click here to manage your notifications</a>.
</p>
</div>
</td>
</tr>

View File

@ -286,9 +286,12 @@
style="font-size:0px;padding:10px 25px;padding-top:0px;padding-bottom:0px;word-break:break-word;">
<div
style="font-family:Arial, sans-serif;font-size:11px;letter-spacing:normal;line-height:22px;text-align:center;color:#000000;">
<p style="margin: 10px 0;">This e-mail has been sent to {{name}}, <a
href="{{unsubscribeLink}}” style=" color:inherit;text-decoration:none;"
target="_blank">click here to unsubscribe</a>.</p>
<p style="margin: 10px 0;">This e-mail has been sent to {{name}},
<a href="{{unsubscribeLink}}" style="
color: inherit;
text-decoration: none;
" target="_blank">click here to manage your notifications</a>.
</p>
</div>
</td>
</tr>

View File

@ -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} <info@manifold.markets>`
@ -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]

View File

@ -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<keyof notification_subscription_types> = [
'trending_markets',
'profit_loss_updates',
'onboarding_flow',
'thank_you_for_purchases',
]
const watched_markets_explanations_comments: {
type sectionData = {
label: string
subscriptionTypeToDescription: {
[key in keyof Partial<notification_subscription_types>]: 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<notification_subscription_types>]: 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',
}
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 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 watched_markets_explanations_your_markets: {
[key in keyof Partial<notification_subscription_types>]: string
} = {
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 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 watched_markets_explanations_market_updates: {
[key in keyof Partial<notification_subscription_types>]: 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',
}
const bonuses_explanations: {
[key in keyof Partial<notification_subscription_types>]: string
} = {
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 other_balance_change_explanations: {
[key in keyof Partial<notification_subscription_types>]: string
} = {
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 general_explanations: {
[key in keyof Partial<notification_subscription_types>]: string
} = {
const userInteractions: sectionData = {
label: 'Users',
subscriptionTypeToDescription: {
tagged_user: 'A user tagged you',
trending_markets: 'Weekly trending markets',
// profit_loss_updates: 'Weekly profit/loss updates',
}
const follows_and_followers_explanations: {
[key in keyof Partial<notification_subscription_types>]: string
} = {
on_new_follow: 'New followers',
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 (
<Row className={clsx('my-1 gap-1 text-gray-300')}>
<Row
className={clsx(
'my-1 gap-1 text-gray-300',
highlight ? 'rounded-md bg-indigo-100 p-1' : ''
)}
>
<Col className="ml-3 gap-2 text-sm">
<Row className="gap-2 font-medium text-gray-700">
<span>{description}</span>
@ -251,16 +279,20 @@ export function NotificationSettings() {
return privateUser.notificationSubscriptionTypes[key] ?? []
}
const Section = (
icon: ReactNode,
label: string,
subscriptionTypeToDescription: {
[key in keyof Partial<notification_subscription_types>]: 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 (
<Col className={'ml-2 gap-2'}>
<Col className={clsx('ml-2 gap-2')}>
<Row
className={'mt-1 cursor-pointer items-center gap-2 text-gray-600'}
onClick={() => setExpanded(!expanded)}
@ -303,52 +335,20 @@ export function NotificationSettings() {
onClick={() => setShowWatchModal(true)}
/>
</Row>
{Section(
<ChatIcon className={'h-6 w-6'} />,
'New Comments',
watched_markets_explanations_comments
)}
{Section(
<LightBulbIcon className={'h-6 w-6'} />,
'New Answers',
watched_markets_explanations_answers
)}
{Section(
<TrendingUpIcon className={'h-6 w-6'} />,
'Updates & Resolutions',
watched_markets_explanations_market_updates
)}
{Section(
<UserIcon className={'h-6 w-6'} />,
'Markets You Created',
watched_markets_explanations_your_markets
)}
{Section(<ChatIcon className={'h-6 w-6'} />, comments)}
{Section(<LightBulbIcon className={'h-6 w-6'} />, answers)}
{Section(<TrendingUpIcon className={'h-6 w-6'} />, updates)}
{Section(<UserIcon className={'h-6 w-6'} />, yourMarkets)}
<Row className={'gap-2 text-xl text-gray-700'}>
<span>Balance Changes</span>
</Row>
{Section(
<CurrencyDollarIcon className={'h-6 w-6'} />,
'Bonuses',
bonuses_explanations
)}
{Section(
<CashIcon className={'h-6 w-6'} />,
'Other',
other_balance_change_explanations
)}
{Section(<CurrencyDollarIcon className={'h-6 w-6'} />, bonuses)}
{Section(<CashIcon className={'h-6 w-6'} />, otherBalances)}
<Row className={'gap-2 text-xl text-gray-700'}>
<span>General</span>
</Row>
{Section(
<UsersIcon className={'h-6 w-6'} />,
'Follows & Followers',
follows_and_followers_explanations
)}
{Section(
<InboxInIcon className={'h-6 w-6'} />,
'Other',
general_explanations
)}
{Section(<UsersIcon className={'h-6 w-6'} />, userInteractions)}
{Section(<InboxInIcon className={'h-6 w-6'} />, generalOther)}
<WatchMarketModal open={showWatchModal} setOpen={setShowWatchModal} />
</Col>
</div>

View File

@ -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<string>()
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 (
<Page>
<div className={'px-2 pt-4 sm:px-4 lg:pt-0'}>
<Title text={'Notifications'} className={'hidden md:block'} />
<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}
/>
),
},
]}