diff --git a/web/components/NotificationSettings.tsx b/web/components/NotificationSettings.tsx new file mode 100644 index 00000000..2c657857 --- /dev/null +++ b/web/components/NotificationSettings.tsx @@ -0,0 +1,210 @@ +import { useUser } from 'web/hooks/use-user' +import React, { useEffect, useState } from 'react' +import { notification_subscribe_types, PrivateUser } from 'common/lib/user' +import { listenForPrivateUser, updatePrivateUser } from 'web/lib/firebase/users' +import toast from 'react-hot-toast' +import { track } from '@amplitude/analytics-browser' +import { LoadingIndicator } from 'web/components/loading-indicator' +import { Row } from 'web/components/layout/row' +import clsx from 'clsx' +import { CheckIcon, XIcon } from '@heroicons/react/outline' +import { ChoicesToggleGroup } from 'web/components/choices-toggle-group' + +export function NotificationSettings() { + const user = useUser() + const [notificationSettings, setNotificationSettings] = + useState<notification_subscribe_types>('all') + const [emailNotificationSettings, setEmailNotificationSettings] = + useState<notification_subscribe_types>('all') + const [privateUser, setPrivateUser] = useState<PrivateUser | null>(null) + + useEffect(() => { + if (user) listenForPrivateUser(user.id, setPrivateUser) + }, [user]) + + useEffect(() => { + if (!privateUser) return + if (privateUser.notificationPreferences) { + setNotificationSettings(privateUser.notificationPreferences) + } + if ( + privateUser.unsubscribedFromResolutionEmails && + privateUser.unsubscribedFromCommentEmails && + privateUser.unsubscribedFromAnswerEmails + ) { + setEmailNotificationSettings('none') + } else if ( + !privateUser.unsubscribedFromResolutionEmails && + !privateUser.unsubscribedFromCommentEmails && + !privateUser.unsubscribedFromAnswerEmails + ) { + setEmailNotificationSettings('all') + } else { + setEmailNotificationSettings('less') + } + }, [privateUser]) + + const loading = 'Changing Notifications Settings' + const success = 'Notification Settings Changed!' + function changeEmailNotifications(newValue: notification_subscribe_types) { + if (!privateUser) return + if (newValue === 'all') { + toast.promise( + updatePrivateUser(privateUser.id, { + unsubscribedFromResolutionEmails: false, + unsubscribedFromCommentEmails: false, + unsubscribedFromAnswerEmails: false, + }), + { + loading, + success, + error: (err) => `${err.message}`, + } + ) + } else if (newValue === 'less') { + toast.promise( + updatePrivateUser(privateUser.id, { + unsubscribedFromResolutionEmails: false, + unsubscribedFromCommentEmails: true, + unsubscribedFromAnswerEmails: true, + }), + { + loading, + success, + error: (err) => `${err.message}`, + } + ) + } else if (newValue === 'none') { + toast.promise( + updatePrivateUser(privateUser.id, { + unsubscribedFromResolutionEmails: true, + unsubscribedFromCommentEmails: true, + unsubscribedFromAnswerEmails: true, + }), + { + loading, + success, + error: (err) => `${err.message}`, + } + ) + } + } + + function changeInAppNotificationSettings( + newValue: notification_subscribe_types + ) { + if (!privateUser) return + track('In-App Notification Preferences Changed', { + newPreference: newValue, + oldPreference: privateUser.notificationPreferences, + }) + toast.promise( + updatePrivateUser(privateUser.id, { + notificationPreferences: newValue, + }), + { + loading, + success, + error: (err) => `${err.message}`, + } + ) + } + + useEffect(() => { + if (privateUser && privateUser.notificationPreferences) + setNotificationSettings(privateUser.notificationPreferences) + else setNotificationSettings('all') + }, [privateUser]) + + if (!privateUser) { + return <LoadingIndicator spinnerClassName={'border-gray-500 h-4 w-4'} /> + } + + function NotificationSettingLine(props: { + label: string + highlight: boolean + }) { + const { label, highlight } = props + return ( + <Row className={clsx('my-1 text-gray-300', highlight && '!text-black')}> + {highlight ? <CheckIcon height={20} /> : <XIcon height={20} />} + {label} + </Row> + ) + } + + return ( + <div className={'p-2'}> + <div>In App Notifications</div> + <ChoicesToggleGroup + currentChoice={notificationSettings} + choicesMap={{ All: 'all', Less: 'less', None: 'none' }} + setChoice={(choice) => + changeInAppNotificationSettings( + choice as notification_subscribe_types + ) + } + className={'col-span-4 p-2'} + toggleClassName={'w-24'} + /> + <div className={'mt-4 text-sm'}> + <div> + <div className={''}> + You will receive notifications for: + <NotificationSettingLine + label={"Resolution of questions you've interacted with"} + highlight={notificationSettings !== 'none'} + /> + <NotificationSettingLine + highlight={notificationSettings !== 'none'} + label={'Activity on your own questions, comments, & answers'} + /> + <NotificationSettingLine + highlight={notificationSettings !== 'none'} + label={"Activity on questions you're betting on"} + /> + <NotificationSettingLine + highlight={notificationSettings !== 'none'} + label={"Income & referral bonuses you've received"} + /> + <NotificationSettingLine + label={"Activity on questions you've ever bet or commented on"} + highlight={notificationSettings === 'all'} + /> + </div> + </div> + </div> + <div className={'mt-4'}>Email Notifications</div> + <ChoicesToggleGroup + currentChoice={emailNotificationSettings} + choicesMap={{ All: 'all', Less: 'less', None: 'none' }} + setChoice={(choice) => + changeEmailNotifications(choice as notification_subscribe_types) + } + className={'col-span-4 p-2'} + toggleClassName={'w-24'} + /> + <div className={'mt-4 text-sm'}> + <div> + You will receive emails for: + <NotificationSettingLine + label={"Resolution of questions you're betting on"} + highlight={emailNotificationSettings !== 'none'} + /> + <NotificationSettingLine + label={'Closure of your questions'} + highlight={emailNotificationSettings !== 'none'} + /> + <NotificationSettingLine + label={'Activity on your questions'} + highlight={emailNotificationSettings === 'all'} + /> + <NotificationSettingLine + label={"Activity on questions you've answered or commented on"} + highlight={emailNotificationSettings === 'all'} + /> + </div> + </div> + </div> + ) +} diff --git a/web/pages/notifications.tsx b/web/pages/notifications.tsx index 7867e197..0d5ecdb9 100644 --- a/web/pages/notifications.tsx +++ b/web/pages/notifications.tsx @@ -1,5 +1,5 @@ import { Tabs } from 'web/components/layout/tabs' -import { usePrivateUser, useUser } from 'web/hooks/use-user' +import { usePrivateUser } from 'web/hooks/use-user' import React, { useEffect, useMemo, useState } from 'react' import { Notification, notification_source_types } from 'common/notification' import { Avatar, EmptyAvatar } from 'web/components/avatar' @@ -12,16 +12,10 @@ import { UserLink } from 'web/components/user-page' import { MANIFOLD_AVATAR_URL, MANIFOLD_USERNAME, - notification_subscribe_types, PrivateUser, User, } from 'common/user' -import { ChoicesToggleGroup } from 'web/components/choices-toggle-group' -import { - getUser, - listenForPrivateUser, - updatePrivateUser, -} from 'web/lib/firebase/users' +import { getUser } from 'web/lib/firebase/users' import { LoadingIndicator } from 'web/components/loading-indicator' import clsx from 'clsx' import { RelativeTimestamp } from 'web/components/relative-timestamp' @@ -37,8 +31,7 @@ import { NotificationGroup, usePreferredGroupedNotifications, } from 'web/hooks/use-notifications' -import { CheckIcon, TrendingUpIcon, XIcon } from '@heroicons/react/outline' -import toast from 'react-hot-toast' +import { TrendingUpIcon } from '@heroicons/react/outline' import { formatMoney } from 'common/util/format' import { groupPath } from 'web/lib/firebase/groups' import { UNIQUE_BETTOR_BONUS_AMOUNT } from 'common/numeric-constants' @@ -53,6 +46,7 @@ import { redirectIfLoggedOut, } from 'web/lib/firebase/server-auth' import { SiteLink } from 'web/components/site-link' +import { NotificationSettings } from 'web/components/NotificationSettings' export const NOTIFICATIONS_PER_PAGE = 30 const MULTIPLE_USERS_KEY = 'multipleUsers' @@ -986,203 +980,3 @@ function getReasonForShowingNotification( } return reasonText } - -// TODO: where should we put referral bonus notifications? -function NotificationSettings() { - const user = useUser() - const [notificationSettings, setNotificationSettings] = - useState<notification_subscribe_types>('all') - const [emailNotificationSettings, setEmailNotificationSettings] = - useState<notification_subscribe_types>('all') - const [privateUser, setPrivateUser] = useState<PrivateUser | null>(null) - - useEffect(() => { - if (user) listenForPrivateUser(user.id, setPrivateUser) - }, [user]) - - useEffect(() => { - if (!privateUser) return - if (privateUser.notificationPreferences) { - setNotificationSettings(privateUser.notificationPreferences) - } - if ( - privateUser.unsubscribedFromResolutionEmails && - privateUser.unsubscribedFromCommentEmails && - privateUser.unsubscribedFromAnswerEmails - ) { - setEmailNotificationSettings('none') - } else if ( - !privateUser.unsubscribedFromResolutionEmails && - !privateUser.unsubscribedFromCommentEmails && - !privateUser.unsubscribedFromAnswerEmails - ) { - setEmailNotificationSettings('all') - } else { - setEmailNotificationSettings('less') - } - }, [privateUser]) - - const loading = 'Changing Notifications Settings' - const success = 'Notification Settings Changed!' - function changeEmailNotifications(newValue: notification_subscribe_types) { - if (!privateUser) return - if (newValue === 'all') { - toast.promise( - updatePrivateUser(privateUser.id, { - unsubscribedFromResolutionEmails: false, - unsubscribedFromCommentEmails: false, - unsubscribedFromAnswerEmails: false, - }), - { - loading, - success, - error: (err) => `${err.message}`, - } - ) - } else if (newValue === 'less') { - toast.promise( - updatePrivateUser(privateUser.id, { - unsubscribedFromResolutionEmails: false, - unsubscribedFromCommentEmails: true, - unsubscribedFromAnswerEmails: true, - }), - { - loading, - success, - error: (err) => `${err.message}`, - } - ) - } else if (newValue === 'none') { - toast.promise( - updatePrivateUser(privateUser.id, { - unsubscribedFromResolutionEmails: true, - unsubscribedFromCommentEmails: true, - unsubscribedFromAnswerEmails: true, - }), - { - loading, - success, - error: (err) => `${err.message}`, - } - ) - } - } - - function changeInAppNotificationSettings( - newValue: notification_subscribe_types - ) { - if (!privateUser) return - track('In-App Notification Preferences Changed', { - newPreference: newValue, - oldPreference: privateUser.notificationPreferences, - }) - toast.promise( - updatePrivateUser(privateUser.id, { - notificationPreferences: newValue, - }), - { - loading, - success, - error: (err) => `${err.message}`, - } - ) - } - - useEffect(() => { - if (privateUser && privateUser.notificationPreferences) - setNotificationSettings(privateUser.notificationPreferences) - else setNotificationSettings('all') - }, [privateUser]) - - if (!privateUser) { - return <LoadingIndicator spinnerClassName={'border-gray-500 h-4 w-4'} /> - } - - function NotificationSettingLine(props: { - label: string - highlight: boolean - }) { - const { label, highlight } = props - return ( - <Row className={clsx('my-1 text-gray-300', highlight && '!text-black')}> - {highlight ? <CheckIcon height={20} /> : <XIcon height={20} />} - {label} - </Row> - ) - } - - return ( - <div className={'p-2'}> - <div>In App Notifications</div> - <ChoicesToggleGroup - currentChoice={notificationSettings} - choicesMap={{ All: 'all', Less: 'less', None: 'none' }} - setChoice={(choice) => - changeInAppNotificationSettings( - choice as notification_subscribe_types - ) - } - className={'col-span-4 p-2'} - toggleClassName={'w-24'} - /> - <div className={'mt-4 text-sm'}> - <div> - <div className={''}> - You will receive notifications for: - <NotificationSettingLine - label={"Resolution of questions you've interacted with"} - highlight={notificationSettings !== 'none'} - /> - <NotificationSettingLine - highlight={notificationSettings !== 'none'} - label={'Activity on your own questions, comments, & answers'} - /> - <NotificationSettingLine - highlight={notificationSettings !== 'none'} - label={"Activity on questions you're betting on"} - /> - <NotificationSettingLine - highlight={notificationSettings !== 'none'} - label={"Income & referral bonuses you've received"} - /> - <NotificationSettingLine - label={"Activity on questions you've ever bet or commented on"} - highlight={notificationSettings === 'all'} - /> - </div> - </div> - </div> - <div className={'mt-4'}>Email Notifications</div> - <ChoicesToggleGroup - currentChoice={emailNotificationSettings} - choicesMap={{ All: 'all', Less: 'less', None: 'none' }} - setChoice={(choice) => - changeEmailNotifications(choice as notification_subscribe_types) - } - className={'col-span-4 p-2'} - toggleClassName={'w-24'} - /> - <div className={'mt-4 text-sm'}> - <div> - You will receive emails for: - <NotificationSettingLine - label={"Resolution of questions you're betting on"} - highlight={emailNotificationSettings !== 'none'} - /> - <NotificationSettingLine - label={'Closure of your questions'} - highlight={emailNotificationSettings !== 'none'} - /> - <NotificationSettingLine - label={'Activity on your questions'} - highlight={emailNotificationSettings === 'all'} - /> - <NotificationSettingLine - label={"Activity on questions you've answered or commented on"} - highlight={emailNotificationSettings === 'all'} - /> - </div> - </div> - </div> - ) -}