use-project-notification-preferences.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import { useCallback, useEffect, useState } from 'react'
  2. import { useProjectContext } from '@/shared/context/project-context'
  3. import { getJSON, postJSON } from '@/infrastructure/fetch-json'
  4. import { debugConsole } from '@/utils/debugging'
  5. import type { NotificationPreferencesSchema } from '../../../../../modules/notifications/app/src/types.js'
  6. import { sendMB } from '@/infrastructure/event-tracking'
  7. import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
  8. export type NotificationLevel = 'all' | 'replies' | 'off'
  9. /**
  10. * Map UI notification level to backend preferences
  11. */
  12. function levelToPreferences(
  13. level: NotificationLevel
  14. ): NotificationPreferencesSchema {
  15. switch (level) {
  16. case 'all':
  17. return {
  18. trackedChangesOnOwnProject: true,
  19. trackedChangesOnInvitedProject: true,
  20. commentOnOwnProject: true,
  21. commentOnInvitedProject: true,
  22. repliesOnOwnProject: true,
  23. repliesOnInvitedProject: true,
  24. repliesOnAuthoredThread: true,
  25. repliesOnParticipatingThread: true,
  26. }
  27. case 'replies':
  28. return {
  29. trackedChangesOnOwnProject: false,
  30. trackedChangesOnInvitedProject: false,
  31. commentOnOwnProject: false,
  32. commentOnInvitedProject: false,
  33. repliesOnOwnProject: false,
  34. repliesOnInvitedProject: false,
  35. repliesOnAuthoredThread: true,
  36. repliesOnParticipatingThread: true,
  37. }
  38. case 'off':
  39. return {
  40. trackedChangesOnOwnProject: false,
  41. trackedChangesOnInvitedProject: false,
  42. commentOnOwnProject: false,
  43. commentOnInvitedProject: false,
  44. repliesOnOwnProject: false,
  45. repliesOnInvitedProject: false,
  46. repliesOnAuthoredThread: false,
  47. repliesOnParticipatingThread: false,
  48. }
  49. }
  50. }
  51. /**
  52. * Map backend preferences to UI notification level
  53. */
  54. function preferencesToLevel(
  55. preferences: NotificationPreferencesSchema
  56. ): NotificationLevel {
  57. // If all notifications are off
  58. if (
  59. !preferences.commentOnOwnProject &&
  60. !preferences.commentOnInvitedProject &&
  61. !preferences.repliesOnOwnProject &&
  62. !preferences.repliesOnInvitedProject &&
  63. !preferences.repliesOnAuthoredThread &&
  64. !preferences.repliesOnParticipatingThread
  65. ) {
  66. return 'off'
  67. }
  68. // If only reply-related notifications are on
  69. if (
  70. !preferences.commentOnOwnProject &&
  71. !preferences.commentOnInvitedProject &&
  72. (preferences.repliesOnAuthoredThread ||
  73. preferences.repliesOnParticipatingThread)
  74. ) {
  75. return 'replies'
  76. }
  77. // Default to 'all' for any other combination
  78. return 'all'
  79. }
  80. export function useProjectNotificationPreferences() {
  81. const { projectId } = useProjectContext()
  82. const { permissionsLevel } = useIdeReactContext()
  83. const [notificationLevel, setNotificationLevel] =
  84. useState<NotificationLevel>('all')
  85. const [isLoading, setIsLoading] = useState(true)
  86. // Load preferences on mount
  87. useEffect(() => {
  88. getJSON<NotificationPreferencesSchema>(
  89. `/notifications/preferences/project/${projectId}`
  90. )
  91. .then(prefs => {
  92. setNotificationLevel(preferencesToLevel(prefs))
  93. })
  94. .catch(debugConsole.error)
  95. .finally(() => setIsLoading(false))
  96. }, [projectId])
  97. const setLevel = useCallback(
  98. (level: NotificationLevel) => {
  99. setNotificationLevel(level)
  100. const preferences = levelToPreferences(level)
  101. sendMB('setting-changed', {
  102. changedSetting: 'projectEmailNotifications',
  103. changedSettingVal: level,
  104. projectRole: permissionsLevel,
  105. })
  106. postJSON(`/notifications/preferences/project/${projectId}`, {
  107. body: preferences,
  108. }).catch(debugConsole.error)
  109. },
  110. [projectId, permissionsLevel]
  111. )
  112. return {
  113. notificationLevel,
  114. setNotificationLevel: setLevel,
  115. isLoading,
  116. }
  117. }