Просмотр исходного кода

Merge pull request #32949 from overleaf/kh-default-invitees-to-replies-only

[web] default invitees to replies only

GitOrigin-RevId: e3198403917e2679e49e27aaa87ae111675dc974
Kristina 3 месяцев назад
Родитель
Сommit
40954ae2dc

+ 27 - 21
services/web/frontend/js/features/settings/hooks/use-project-notification-preferences.ts

@@ -8,6 +8,7 @@ import type {
 } from '../../../../../modules/notifications/app/src/types.js'
 import { sendMB } from '@/infrastructure/event-tracking'
 import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
+import { type PermissionsLevel } from '@/features/ide-react/types/permissions'
 
 export type SettableNotificationLevel = 'all' | 'replies' | 'off'
 export type NotificationLevel = SettableNotificationLevel | 'global-off'
@@ -56,38 +57,43 @@ function levelToPreferences(
 }
 
 /**
- * Map backend preferences to UI notification level
+ * Map backend preferences to UI notification level, considering the user's
+ * role so that only the relevant key variant is inspected.
  */
 function preferencesToLevel(
-  preferences: GlobalNotificationPreferencesSchema
+  preferences: GlobalNotificationPreferencesSchema,
+  permissionsLevel: PermissionsLevel
 ): NotificationLevel {
   if (preferences.muteAllNotifications) {
     return 'global-off'
   }
 
-  // If all notifications are off
-  if (
-    !preferences.commentOnOwnProject &&
-    !preferences.commentOnInvitedProject &&
-    !preferences.repliesOnOwnProject &&
-    !preferences.repliesOnInvitedProject &&
-    !preferences.repliesOnAuthoredThread &&
-    !preferences.repliesOnParticipatingThread
-  ) {
+  const isOwner = permissionsLevel === 'owner'
+
+  const projectComments = isOwner
+    ? preferences.commentOnOwnProject
+    : preferences.commentOnInvitedProject
+  const projectTrackedChanges = isOwner
+    ? preferences.trackedChangesOnOwnProject
+    : preferences.trackedChangesOnInvitedProject
+  const projectReplies = isOwner
+    ? preferences.repliesOnOwnProject
+    : preferences.repliesOnInvitedProject
+
+  const anyProjectNotifications =
+    projectComments || projectTrackedChanges || projectReplies
+  const anyParticipantNotifications =
+    preferences.repliesOnAuthoredThread ||
+    preferences.repliesOnParticipatingThread
+
+  if (!anyProjectNotifications && !anyParticipantNotifications) {
     return 'off'
   }
 
-  // If only reply-related notifications are on
-  if (
-    !preferences.commentOnOwnProject &&
-    !preferences.commentOnInvitedProject &&
-    (preferences.repliesOnAuthoredThread ||
-      preferences.repliesOnParticipatingThread)
-  ) {
+  if (!anyProjectNotifications && anyParticipantNotifications) {
     return 'replies'
   }
 
-  // Default to 'all' for any other combination
   return 'all'
 }
 
@@ -104,11 +110,11 @@ export function useProjectNotificationPreferences() {
       `/notifications/preferences/project/${projectId}`
     )
       .then(prefs => {
-        setNotificationLevel(preferencesToLevel(prefs))
+        setNotificationLevel(preferencesToLevel(prefs, permissionsLevel))
       })
       .catch(debugConsole.error)
       .finally(() => setIsLoading(false))
-  }, [projectId])
+  }, [projectId, permissionsLevel])
 
   const setLevel = useCallback(
     (level: SettableNotificationLevel) => {

+ 48 - 2
services/web/test/frontend/features/settings-modal/settings/project-notifications-setting.test.tsx

@@ -53,9 +53,21 @@ const allNotificationsOff = {
   repliesOnParticipatingThread: false,
 }
 
-function renderComponent() {
+const defaultPreferences = {
+  trackedChangesOnOwnProject: true,
+  trackedChangesOnInvitedProject: false,
+  commentOnOwnProject: true,
+  commentOnInvitedProject: false,
+  repliesOnOwnProject: false,
+  repliesOnInvitedProject: false,
+  repliesOnAuthoredThread: true,
+  repliesOnParticipatingThread: true,
+  muteAllNotifications: false,
+}
+
+function renderComponent(props: { permissionsLevel?: string } = {}) {
   return render(
-    <EditorProviders>
+    <EditorProviders permissionsLevel={props.permissionsLevel as any}>
       <SettingsModalProvider>
         <ProjectNotificationsSetting />
       </SettingsModalProvider>
@@ -241,6 +253,40 @@ describe('<ProjectNotificationsSetting />', function () {
     ).to.be.true
   })
 
+  it('shows "all" for owner with default preferences', async function () {
+    fetchMock.get(preferencesUrl, defaultPreferences)
+
+    renderComponent({ permissionsLevel: 'owner' })
+
+    await waitFor(
+      () =>
+        expect(
+          (
+            screen.getByLabelText('All project activity', {
+              exact: false,
+            }) as HTMLInputElement
+          ).checked
+        ).to.be.true
+    )
+  })
+
+  it('shows "replies" for invitee with default preferences', async function () {
+    fetchMock.get(preferencesUrl, defaultPreferences)
+
+    renderComponent({ permissionsLevel: 'readAndWrite' })
+
+    await waitFor(
+      () =>
+        expect(
+          (
+            screen.getByLabelText('Replies to your activity only', {
+              exact: false,
+            }) as HTMLInputElement
+          ).checked
+        ).to.be.true
+    )
+  })
+
   it('POSTs "all" preferences when "All project activity" is selected', async function () {
     fetchMock.get(preferencesUrl, allNotificationsOff)
     const saveMock = fetchMock.post(preferencesUrl, { status: 200 })