Add Notification Preferences Page To User Settings (#30116)

* changing to pug conditional format for admin page conditional render

* feat: update notifications settings page and open BE route

feat: adding new page for notification prefs on user settings, along with updating saving prefs for global preferences

adding error handling and disabling when request is inflight

formatting and adding split test for viewing notification ettings

fix: updating to levels of preferences, and removing global type for preferences as we will now share the same backing settings between global and project preferences

feat: add global mute to user settings for notifications

making params in preferences schema optional

feat: update global settings to only set mute, and remove optional settings

fix: store userId as objectId, and filter based on global mute setting
GitOrigin-RevId: 947a95dc02d12b4a2d8e3cc29bd04c23af2aef25
This commit is contained in:
Jimmy Domagala-Tang
2026-01-07 11:41:33 -05:00
committed by Copybot
parent 9a6c2edf16
commit 75734993e7
9 changed files with 65 additions and 8 deletions
@@ -11,6 +11,7 @@ import _ from 'lodash'
import { expressify } from '@overleaf/promise-utils'
import Features from '../../infrastructure/Features.mjs'
import Modules from '../../infrastructure/Modules.mjs'
import SplitTestHandler from '../SplitTests/SplitTestHandler.mjs'
async function settingsPage(req, res) {
const userId = SessionManager.getLoggedInUserId(req.session)
@@ -116,6 +117,8 @@ async function settingsPage(req, res) {
)
}
await SplitTestHandler.promises.getAssignment(req, res, 'email-notifications')
res.render('user/settings', {
title: 'account_settings',
user: {
@@ -550,6 +550,7 @@
"email_must_be_linked_to_institution": "",
"email_notifications_are_currently_in_beta": "",
"email_or_password_wrong_try_again": "",
"email_preferences": "",
"email_remove_by_date": "",
"emails_and_affiliations_explanation": "",
"emails_and_affiliations_title": "",
@@ -1047,6 +1048,7 @@
"make_primary": "",
"make_private": "",
"manage_beta_program_membership": "",
"manage_email_preferences": "",
"manage_files_from_your_dropbox_folder": "",
"manage_group_members_subtext": "",
"manage_group_settings": "",
@@ -1142,6 +1144,7 @@
"new_tag": "",
"new_tag_name": "",
"newsletter": "",
"newsletter_info_note": "",
"newsletter_onboarding_accept": "",
"next": "",
"next_page": "",
@@ -0,0 +1,16 @@
import { useTranslation } from 'react-i18next'
function NotificationsSection() {
const { t } = useTranslation()
return (
<>
<h3>{t('email_preferences')}</h3>
<a href="/user/notification-preferences">
{t('manage_email_preferences')}
</a>
</>
)
}
export default NotificationsSection
@@ -15,13 +15,14 @@ import LeaveSection from './leave-section'
import * as eventTracking from '../../../infrastructure/event-tracking'
import { UserProvider } from '../../../shared/context/user-context'
import { SSOProvider } from '../context/sso-context'
import { SplitTestProvider } from '@/shared/context/split-test-context'
import useWaitForI18n from '../../../shared/hooks/use-wait-for-i18n'
import useScrollToIdOnLoad from '../../../shared/hooks/use-scroll-to-id-on-load'
import { SSOAlert } from './emails/sso-alert'
import OLRow from '@/shared/components/ol/ol-row'
import OLCol from '@/shared/components/ol/ol-col'
import OLPageContentCard from '@/shared/components/ol/ol-page-content-card'
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
import NotificationsSection from './notifications-section'
function SettingsPageRoot() {
const { isReady } = useWaitForI18n()
@@ -45,7 +46,7 @@ function SettingsPageRoot() {
function SettingsPageContent() {
const { t } = useTranslation()
const { isOverleaf, labsEnabled } = getMeta('ol-ExposedSettings')
const inNotificationsSplitTest = isSplitTestEnabled('email-notifications')
return (
<UserProvider>
<OLPageContentCard>
@@ -66,11 +67,9 @@ function SettingsPageContent() {
</OLRow>
<hr />
<SecuritySection />
<SplitTestProvider>
<SSOProvider>
<LinkingSection />
</SSOProvider>
</SplitTestProvider>
<SSOProvider>
<LinkingSection />
</SSOProvider>
{isOverleaf ? (
<>
<BetaProgramSection />
@@ -86,7 +85,11 @@ function SettingsPageContent() {
{isOverleaf ? (
<>
<hr />
<NewsletterSection />
{inNotificationsSplitTest ? (
<NotificationsSection />
) : (
<NewsletterSection />
)}
<hr />
<LeaveSection />
</>
+2
View File
@@ -66,6 +66,7 @@ import { Subscription as AdminSubscription } from '../../../types/admin/subscrip
import { AdminCapability } from '../../../types/admin-capabilities'
import { AlgoliaConfig } from '../../../modules/algolia-search/frontend/js/types'
import { WritefullPublicEnv } from '@wf/domain/writefull-public-env'
import { UserNotificationPreferences } from '../../../types/notifications'
export interface Meta {
'ol-ExposedSettings': ExposedSettings
@@ -317,6 +318,7 @@ export interface Meta {
'ol-userCanExtendTrial': boolean
'ol-userCanNotStartRequestedTrial': boolean
'ol-userEmails': UserEmailData[]
'ol-userNotificationPreferences': UserNotificationPreferences
'ol-userSettings': UserSettings
'ol-user_id': string | undefined
'ol-users': ManagedUser[]
@@ -60,3 +60,4 @@
@import 'portals';
@import 'wiki';
@import 'templates';
@import 'notification-settings';
@@ -0,0 +1,20 @@
.notification-settings-container {
input {
margin-top: var(--spacing-01);
margin-bottom: auto;
accent-color: var(--green-50);
}
.setting-container {
display: flex;
gap: 10px;
}
h2 {
margin-bottom: 0;
}
h4 {
margin-bottom: 0;
}
}
+2
View File
@@ -698,6 +698,7 @@
"email_notifications_are_currently_in_beta": "Email notifications are currently in beta.",
"email_or_password_wrong_try_again": "Your email or password is incorrect. Please try again.",
"email_or_password_wrong_try_again_or_reset": "Your email or password is incorrect. Please try again, or <0>set or reset your password</0>.",
"email_preferences": "Email preferences",
"email_remove_by_date": "If this is not done by __date__, it will be removed from the account.",
"email_required": "Email required",
"email_sent": "Email Sent",
@@ -1363,6 +1364,7 @@
"make_primary": "Make primary",
"make_private": "Make private",
"manage_beta_program_membership": "Manage beta program membership",
"manage_email_preferences": "Manage email preferences",
"manage_files_from_your_dropbox_folder": "Manage files from your Dropbox folder",
"manage_group_members_subtext": "Add or remove members from your group subscription",
"manage_group_settings": "Manage group settings",
+7
View File
@@ -0,0 +1,7 @@
type GlobalNotificationPreferences = {
muteAllNotifications: boolean
}
export type UserNotificationPreferences = {
newsletter: boolean
} & GlobalNotificationPreferences