diff --git a/lib/shared/thread-settings-notifications-utils.js b/lib/shared/thread-settings-notifications-utils.js new file mode 100644 --- /dev/null +++ b/lib/shared/thread-settings-notifications-utils.js @@ -0,0 +1,110 @@ +// @flow + +import * as React from 'react'; + +import { + updateSubscriptionActionTypes, + useUpdateSubscription, +} from '../actions/user-actions.js'; +import { createLoadingStatusSelector } from '../selectors/loading-selectors.js'; +import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js'; +import { useDispatchActionPromise } from '../utils/redux-promise-utils.js'; +import { useSelector } from '../utils/redux-utils.js'; + +type NotificationSettings = 'focused' | 'badge-only' | 'background'; + +const updateSubscriptionLoadingStatusSelector = createLoadingStatusSelector( + updateSubscriptionActionTypes, +); + +function useThreadSettingsNotifications( + threadInfo: ThreadInfo, + onSuccessCallback: () => mixed, +): { + +notificationSettings: NotificationSettings, + +onFocusedSelected: () => mixed, + +onBadgeOnlySelected: () => mixed, + +onBackgroundSelected: () => mixed, + +saveButtonDisabled: boolean, + +onSave: () => mixed, +} { + const subscription = threadInfo.currentUser.subscription; + + const initialThreadSetting = React.useMemo(() => { + if (!subscription.home) { + return 'background'; + } + if (!subscription.pushNotifs) { + return 'badge-only'; + } + return 'focused'; + }, [subscription.home, subscription.pushNotifs]); + + const [notificationSettings, setNotificationSettings] = + React.useState(initialThreadSetting); + + const onFocusedSelected = React.useCallback( + () => setNotificationSettings('focused'), + [], + ); + const onBadgeOnlySelected = React.useCallback( + () => setNotificationSettings('badge-only'), + [], + ); + const onBackgroundSelected = React.useCallback( + () => setNotificationSettings('background'), + [], + ); + + const dispatchActionPromise = useDispatchActionPromise(); + + const callUpdateSubscription = useUpdateSubscription(); + + const updateSubscriptionPromise = React.useCallback(async () => { + const res = await callUpdateSubscription({ + threadID: threadInfo.id, + updatedFields: { + home: notificationSettings !== 'background', + pushNotifs: notificationSettings === 'focused', + }, + }); + + onSuccessCallback(); + + return res; + }, [ + callUpdateSubscription, + notificationSettings, + onSuccessCallback, + threadInfo.id, + ]); + + const updateSubscriptionLoadingStatus = useSelector( + updateSubscriptionLoadingStatusSelector, + ); + const isLoading = updateSubscriptionLoadingStatus === 'loading'; + const saveButtonDisabled = + isLoading || notificationSettings === initialThreadSetting; + + const onSave = React.useCallback(() => { + if (saveButtonDisabled) { + return; + } + + void dispatchActionPromise( + updateSubscriptionActionTypes, + updateSubscriptionPromise(), + ); + }, [saveButtonDisabled, dispatchActionPromise, updateSubscriptionPromise]); + + return { + notificationSettings, + onFocusedSelected, + onBadgeOnlySelected, + onBackgroundSelected, + saveButtonDisabled, + onSave, + }; +} + +export { useThreadSettingsNotifications }; diff --git a/web/components/enum-settings-option.react.js b/web/components/enum-settings-option.react.js --- a/web/components/enum-settings-option.react.js +++ b/web/components/enum-settings-option.react.js @@ -19,7 +19,7 @@ type Props = { +selected: boolean, - +onSelect: () => void, + +onSelect: () => mixed, +disabled?: boolean, +icon?: React.Node, +title: string, diff --git a/web/modals/threads/notifications/notifications-modal.react.js b/web/modals/threads/notifications/notifications-modal.react.js --- a/web/modals/threads/notifications/notifications-modal.react.js +++ b/web/modals/threads/notifications/notifications-modal.react.js @@ -2,14 +2,10 @@ import * as React from 'react'; -import { - useUpdateSubscription, - updateSubscriptionActionTypes, -} from 'lib/actions/user-actions.js'; import { useCanPromoteSidebar } from 'lib/hooks/promote-sidebar.react.js'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; +import { useThreadSettingsNotifications } from 'lib/shared/thread-settings-notifications-utils.js'; import { threadIsSidebar } from 'lib/shared/thread-utils.js'; -import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import css from './notifications-modal.css'; import AllNotifsIllustration from '../../../assets/all-notifs.react.js'; @@ -20,8 +16,6 @@ import { useSelector } from '../../../redux/redux-utils.js'; import Modal from '../../modal.react.js'; -type NotificationSettings = 'focused' | 'badge-only' | 'background'; - const BANNER_NOTIFS = 'Banner notifs'; const BADGE_COUNT = 'Badge count'; const IN_FOCUSED_TAB = 'Lives in Focused tab'; @@ -88,38 +82,20 @@ function NotificationsModal(props: Props): React.Node { const { onClose, threadID } = props; const threadInfo = useSelector(state => threadInfoSelector(state)[threadID]); - const { subscription } = threadInfo.currentUser; const { parentThreadID } = threadInfo; const parentThreadInfo = useSelector(state => parentThreadID ? threadInfoSelector(state)[parentThreadID] : null, ); const isSidebar = threadIsSidebar(threadInfo); - const initialThreadSetting = React.useMemo(() => { - if (!subscription.home) { - return 'background'; - } - if (!subscription.pushNotifs) { - return 'badge-only'; - } - return 'focused'; - }, [subscription.home, subscription.pushNotifs]); - - const [notificationSettings, setNotificationSettings] = - React.useState(initialThreadSetting); - - const onFocusedSelected = React.useCallback( - () => setNotificationSettings('focused'), - [], - ); - const onBadgeOnlySelected = React.useCallback( - () => setNotificationSettings('badge-only'), - [], - ); - const onBackgroundSelected = React.useCallback( - () => setNotificationSettings('background'), - [], - ); + const { + notificationSettings, + onFocusedSelected, + onBadgeOnlySelected, + onBackgroundSelected, + saveButtonDisabled, + onSave, + } = useThreadSettingsNotifications(threadInfo, onClose); const isFocusedSelected = notificationSettings === 'focused'; const focusedItem = React.useMemo(() => { @@ -164,30 +140,6 @@ ); }, [isBackgroundSelected, onBackgroundSelected, isSidebar]); - const dispatchActionPromise = useDispatchActionPromise(); - - const callUpdateSubscription = useUpdateSubscription(); - - const onClickSave = React.useCallback(() => { - void dispatchActionPromise( - updateSubscriptionActionTypes, - callUpdateSubscription({ - threadID: threadID, - updatedFields: { - home: notificationSettings !== 'background', - pushNotifs: notificationSettings === 'focused', - }, - }), - ); - onClose(); - }, [ - callUpdateSubscription, - dispatchActionPromise, - notificationSettings, - onClose, - threadID, - ]); - const modalName = isSidebar ? 'Thread notifications' : 'Channel notifications'; @@ -270,20 +222,11 @@ } return ( - ); - }, [ - initialThreadSetting, - notificationSettings, - onClickSave, - parentThreadIsInBackground, - ]); + }, [saveButtonDisabled, onSave, parentThreadIsInBackground]); return (