| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- import { useCallback, useEffect, useState } from 'react'
- import { useProjectContext } from '@/shared/context/project-context'
- import { getJSON, postJSON } from '@/infrastructure/fetch-json'
- import { debugConsole } from '@/utils/debugging'
- import type {
- GlobalNotificationPreferencesSchema,
- NotificationPreferencesSchema,
- } 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'
- /**
- * Map UI notification level to backend preferences
- */
- function levelToPreferences(
- level: SettableNotificationLevel
- ): NotificationPreferencesSchema {
- switch (level) {
- case 'all':
- return {
- commentOnOwnProject: true,
- commentOnInvitedProject: true,
- repliesOnAuthoredThread: true,
- repliesOnParticipatingThread: true,
- commentResolvedOnAuthoredThread: true,
- commentResolvedOnParticipatingThread: true,
- commentReopenedOnAuthoredThread: true,
- commentReopenedOnParticipatingThread: true,
- trackedChangesOnOwnProject: true,
- trackedChangesOnInvitedProject: true,
- trackChangesAcceptedOnAuthoredChange: true,
- trackChangesRejectedOnAuthoredChange: true,
- }
- case 'replies':
- return {
- commentOnOwnProject: false,
- commentOnInvitedProject: false,
- repliesOnAuthoredThread: true,
- repliesOnParticipatingThread: true,
- commentResolvedOnAuthoredThread: true,
- commentResolvedOnParticipatingThread: true,
- commentReopenedOnAuthoredThread: true,
- commentReopenedOnParticipatingThread: true,
- trackedChangesOnOwnProject: false,
- trackedChangesOnInvitedProject: false,
- trackChangesAcceptedOnAuthoredChange: true,
- trackChangesRejectedOnAuthoredChange: true,
- }
- case 'off':
- return {
- commentOnOwnProject: false,
- commentOnInvitedProject: false,
- repliesOnAuthoredThread: false,
- repliesOnParticipatingThread: false,
- commentResolvedOnAuthoredThread: false,
- commentResolvedOnParticipatingThread: false,
- commentReopenedOnAuthoredThread: false,
- commentReopenedOnParticipatingThread: false,
- trackedChangesOnOwnProject: false,
- trackedChangesOnInvitedProject: false,
- trackChangesAcceptedOnAuthoredChange: false,
- trackChangesRejectedOnAuthoredChange: false,
- }
- }
- }
- /**
- * 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,
- permissionsLevel: PermissionsLevel
- ): NotificationLevel {
- if (preferences.muteAllNotifications) {
- return 'global-off'
- }
- const isOwner = permissionsLevel === 'owner'
- const projectComments = isOwner
- ? preferences.commentOnOwnProject
- : preferences.commentOnInvitedProject
- const projectTrackedChanges = isOwner
- ? preferences.trackedChangesOnOwnProject
- : preferences.trackedChangesOnInvitedProject
- const anyProjectNotifications = projectComments || projectTrackedChanges
- const anyParticipantNotifications =
- preferences.repliesOnAuthoredThread ||
- preferences.repliesOnParticipatingThread ||
- preferences.trackChangesAcceptedOnAuthoredChange ||
- preferences.trackChangesRejectedOnAuthoredChange ||
- preferences.commentResolvedOnAuthoredThread ||
- preferences.commentResolvedOnParticipatingThread ||
- preferences.commentReopenedOnAuthoredThread ||
- preferences.commentReopenedOnParticipatingThread
- if (!anyProjectNotifications && !anyParticipantNotifications) {
- return 'off'
- }
- if (!anyProjectNotifications && anyParticipantNotifications) {
- return 'replies'
- }
- return 'all'
- }
- export function useProjectNotificationPreferences() {
- const { projectId } = useProjectContext()
- const { permissionsLevel } = useIdeReactContext()
- const [notificationLevel, setNotificationLevel] =
- useState<NotificationLevel>('all')
- const [isLoading, setIsLoading] = useState(true)
- // Load preferences on mount
- useEffect(() => {
- getJSON<GlobalNotificationPreferencesSchema>(
- `/notifications/preferences/project/${projectId}`
- )
- .then(prefs => {
- setNotificationLevel(preferencesToLevel(prefs, permissionsLevel))
- })
- .catch(debugConsole.error)
- .finally(() => setIsLoading(false))
- }, [projectId, permissionsLevel])
- const setLevel = useCallback(
- (level: SettableNotificationLevel) => {
- setNotificationLevel(level)
- const preferences = levelToPreferences(level)
- sendMB('setting-changed', {
- changedSetting: 'projectEmailNotifications',
- changedSettingVal: level,
- projectRole: permissionsLevel,
- })
- postJSON(`/notifications/preferences/project/${projectId}`, {
- body: preferences,
- }).catch(debugConsole.error)
- },
- [projectId, permissionsLevel]
- )
- return {
- notificationLevel,
- setNotificationLevel: setLevel,
- isLoading,
- }
- }
|