diff --git a/web/modals/threads/settings/thread-settings-delete-tab.react.js b/web/modals/threads/settings/thread-settings-delete-tab.react.js --- a/web/modals/threads/settings/thread-settings-delete-tab.react.js +++ b/web/modals/threads/settings/thread-settings-delete-tab.react.js @@ -2,22 +2,14 @@ import * as React from 'react'; -import { - deleteThreadActionTypes, - useDeleteThread, -} from 'lib/actions/thread-actions.js'; -import { useModalContext } from 'lib/components/modal-provider.react.js'; import SWMansionIcon from 'lib/components/SWMansionIcon.react.js'; -import { containedThreadInfos } from 'lib/selectors/thread-selectors.js'; import { type SetState } from 'lib/types/hook-types.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; -import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import SubmitSection from './submit-section.react.js'; -import ThreadDeleteConfirmationModal from './thread-settings-delete-confirmation-modal.react.js'; import css from './thread-settings-delete-tab.css'; +import { useOnDeleteThread } from './thread-settings-utils.js'; import { buttonThemes } from '../../../components/button.react.js'; -import { useSelector } from '../../../redux/redux-utils.js'; type ThreadSettingsDeleteTabProps = { +threadSettingsOperationInProgress: boolean, @@ -36,69 +28,10 @@ errorMessage, } = props; - const modalContext = useModalContext(); - const dispatchActionPromise = useDispatchActionPromise(); - const callDeleteThread = useDeleteThread(); - const containedThreads = useSelector( - state => containedThreadInfos(state)[threadInfo.id], - ); - const shouldUseDeleteConfirmationModal = React.useMemo( - () => containedThreads?.length > 0, - [containedThreads?.length], - ); - - const popThreadDeleteConfirmationModal = React.useCallback(() => { - if (shouldUseDeleteConfirmationModal) { - modalContext.popModal(); - } - }, [modalContext, shouldUseDeleteConfirmationModal]); - const deleteThreadAction = React.useCallback(async () => { - try { - setErrorMessage(''); - const response = await callDeleteThread({ threadID: threadInfo.id }); - popThreadDeleteConfirmationModal(); - modalContext.popModal(); - return response; - } catch (e) { - popThreadDeleteConfirmationModal(); - setErrorMessage( - e.message === 'invalid_credentials' - ? 'permission not granted' - : 'unknown error', - ); - throw e; - } - }, [ - callDeleteThread, - modalContext, - popThreadDeleteConfirmationModal, + const onDeleteThread = useOnDeleteThread({ + threadInfo, setErrorMessage, - threadInfo.id, - ]); - const dispatchDeleteThreadAction = React.useCallback(() => { - void dispatchActionPromise(deleteThreadActionTypes, deleteThreadAction()); - }, [dispatchActionPromise, deleteThreadAction]); - const onDelete = React.useCallback( - (event: SyntheticEvent) => { - event.preventDefault(); - if (shouldUseDeleteConfirmationModal) { - modalContext.pushModal( - , - ); - } else { - dispatchDeleteThreadAction(); - } - }, - [ - dispatchDeleteThreadAction, - modalContext, - shouldUseDeleteConfirmationModal, - threadInfo, - ], - ); + }); return (
@@ -117,7 +50,7 @@ (); React.useEffect(() => { @@ -99,37 +92,12 @@ [setQueuedChanges, threadInfo.color], ); - const changeThreadSettingsAction = React.useCallback(async () => { - try { - setErrorMessage(''); - return await callChangeThreadSettings({ - threadID: threadInfo.id, - changes: queuedChanges, - }); - } catch (e) { - setErrorMessage('unknown_error'); - throw e; - } finally { - setQueuedChanges(Object.freeze({})); - } - }, [ - callChangeThreadSettings, + const onSaveGeneralThreadSettings = useOnSaveGeneralThreadSettings({ + threadInfo, queuedChanges, - setErrorMessage, setQueuedChanges, - threadInfo.id, - ]); - - const onSubmit = React.useCallback( - (event: SyntheticEvent) => { - event.preventDefault(); - void dispatchActionPromise( - changeThreadSettingsActionTypes, - changeThreadSettingsAction(), - ); - }, - [changeThreadSettingsAction, dispatchActionPromise], - ); + setErrorMessage, + }); const threadNameInputDisabled = !threadHasPermission( threadInfo, @@ -188,7 +156,7 @@ {saveButtonContent} diff --git a/web/modals/threads/settings/thread-settings-privacy-tab.react.js b/web/modals/threads/settings/thread-settings-privacy-tab.react.js --- a/web/modals/threads/settings/thread-settings-privacy-tab.react.js +++ b/web/modals/threads/settings/thread-settings-privacy-tab.react.js @@ -2,21 +2,16 @@ import * as React from 'react'; -import { - changeThreadSettingsActionTypes, - useChangeThreadSettings, -} from 'lib/actions/thread-actions.js'; -import { useModalContext } from 'lib/components/modal-provider.react.js'; import SWMansionIcon from 'lib/components/SWMansionIcon.react.js'; import { threadTypeDescriptions } from 'lib/shared/thread-utils.js'; import { type SetState } from 'lib/types/hook-types.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { threadTypes } from 'lib/types/thread-types-enum.js'; import { type ThreadChanges } from 'lib/types/thread-types.js'; -import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import SubmitSection from './submit-section.react.js'; import css from './thread-settings-privacy-tab.css'; +import { useOnSavePrivacyThreadSettings } from './thread-settings-utils.js'; import EnumSettingsOption from '../../../components/enum-settings-option.react.js'; const { COMMUNITY_OPEN_SUBTHREAD, COMMUNITY_SECRET_SUBTHREAD } = threadTypes; @@ -57,48 +52,17 @@ errorMessage, } = props; - const modalContext = useModalContext(); - const dispatchActionPromise = useDispatchActionPromise(); - const callChangeThreadSettings = useChangeThreadSettings(); - const changeQueued: boolean = React.useMemo( () => Object.values(queuedChanges).some(v => v !== null && v !== undefined), [queuedChanges], ); - const changeThreadSettingsAction = React.useCallback(async () => { - try { - setErrorMessage(''); - const response = await callChangeThreadSettings({ - threadID: threadInfo.id, - changes: queuedChanges, - }); - modalContext.popModal(); - return response; - } catch (e) { - setErrorMessage('unknown_error'); - setQueuedChanges(Object.freeze({})); - throw e; - } - }, [ - callChangeThreadSettings, - modalContext, + const onSavePrivacyThreadSettings = useOnSavePrivacyThreadSettings({ + threadInfo, queuedChanges, - setErrorMessage, setQueuedChanges, - threadInfo.id, - ]); - - const onSubmit = React.useCallback( - (event: SyntheticEvent) => { - event.preventDefault(); - void dispatchActionPromise( - changeThreadSettingsActionTypes, - changeThreadSettingsAction(), - ); - }, - [changeThreadSettingsAction, dispatchActionPromise], - ); + setErrorMessage, + }); const onOpenSelected = React.useCallback(() => { setQueuedChanges(prevQueuedChanges => @@ -161,7 +125,7 @@ diff --git a/web/modals/threads/settings/thread-settings-utils.js b/web/modals/threads/settings/thread-settings-utils.js new file mode 100644 --- /dev/null +++ b/web/modals/threads/settings/thread-settings-utils.js @@ -0,0 +1,211 @@ +// @flow + +import * as React from 'react'; + +import { + changeThreadSettingsActionTypes, + useChangeThreadSettings, + deleteThreadActionTypes, + useDeleteThread, +} from 'lib/actions/thread-actions.js'; +import { useModalContext } from 'lib/components/modal-provider.react.js'; +import { containedThreadInfos } from 'lib/selectors/thread-selectors.js'; +import { type SetState } from 'lib/types/hook-types.js'; +import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; +import { type ThreadChanges } from 'lib/types/thread-types.js'; +import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; + +import ThreadDeleteConfirmationModal from './thread-settings-delete-confirmation-modal.react.js'; +import { useSelector } from '../../../redux/redux-utils.js'; + +type UseOnSaveGeneralThreadSettingsParams = { + +threadInfo: ThreadInfo, + +queuedChanges: ThreadChanges, + +setQueuedChanges: SetState, + +setErrorMessage: SetState, +}; + +function useOnSaveGeneralThreadSettings( + params: UseOnSaveGeneralThreadSettingsParams, +): (event: SyntheticEvent) => mixed { + const { threadInfo, queuedChanges, setQueuedChanges, setErrorMessage } = + params; + + const dispatchActionPromise = useDispatchActionPromise(); + const callChangeThreadSettings = useChangeThreadSettings(); + + const changeThreadSettingsAction = React.useCallback(async () => { + try { + setErrorMessage(''); + return await callChangeThreadSettings({ + threadID: threadInfo.id, + changes: queuedChanges, + }); + } catch (e) { + setErrorMessage('unknown_error'); + throw e; + } finally { + setQueuedChanges(Object.freeze({})); + } + }, [ + callChangeThreadSettings, + queuedChanges, + setErrorMessage, + setQueuedChanges, + threadInfo.id, + ]); + + const onSubmit = React.useCallback( + (event: SyntheticEvent) => { + event.preventDefault(); + void dispatchActionPromise( + changeThreadSettingsActionTypes, + changeThreadSettingsAction(), + ); + }, + [changeThreadSettingsAction, dispatchActionPromise], + ); + + return onSubmit; +} + +type UseOnSavePrivacySettingsParams = { + +threadInfo: ThreadInfo, + +queuedChanges: ThreadChanges, + +setQueuedChanges: SetState, + +setErrorMessage: SetState, +}; + +function useOnSavePrivacyThreadSettings( + params: UseOnSavePrivacySettingsParams, +): (event: SyntheticEvent) => mixed { + const { threadInfo, queuedChanges, setQueuedChanges, setErrorMessage } = + params; + + const modalContext = useModalContext(); + const dispatchActionPromise = useDispatchActionPromise(); + const callChangeThreadSettings = useChangeThreadSettings(); + + const changeThreadSettingsAction = React.useCallback(async () => { + try { + setErrorMessage(''); + const response = await callChangeThreadSettings({ + threadID: threadInfo.id, + changes: queuedChanges, + }); + modalContext.popModal(); + return response; + } catch (e) { + setErrorMessage('unknown_error'); + setQueuedChanges(Object.freeze({})); + throw e; + } + }, [ + callChangeThreadSettings, + modalContext, + queuedChanges, + setErrorMessage, + setQueuedChanges, + threadInfo.id, + ]); + + const onSubmit = React.useCallback( + (event: SyntheticEvent) => { + event.preventDefault(); + void dispatchActionPromise( + changeThreadSettingsActionTypes, + changeThreadSettingsAction(), + ); + }, + [changeThreadSettingsAction, dispatchActionPromise], + ); + + return onSubmit; +} + +type UseOnDeleteParams = { + +threadInfo: ThreadInfo, + +setErrorMessage: SetState, +}; + +function useOnDeleteThread( + params: UseOnDeleteParams, +): (event: SyntheticEvent) => mixed { + const { threadInfo, setErrorMessage } = params; + + const modalContext = useModalContext(); + const dispatchActionPromise = useDispatchActionPromise(); + const callDeleteThread = useDeleteThread(); + const containedThreads = useSelector( + state => containedThreadInfos(state)[threadInfo.id], + ); + + const shouldUseDeleteConfirmationModal = React.useMemo( + () => containedThreads?.length > 0, + [containedThreads?.length], + ); + + const popThreadDeleteConfirmationModal = React.useCallback(() => { + if (shouldUseDeleteConfirmationModal) { + modalContext.popModal(); + } + }, [modalContext, shouldUseDeleteConfirmationModal]); + + const deleteThreadAction = React.useCallback(async () => { + try { + setErrorMessage(''); + const response = await callDeleteThread({ threadID: threadInfo.id }); + popThreadDeleteConfirmationModal(); + modalContext.popModal(); + return response; + } catch (e) { + popThreadDeleteConfirmationModal(); + setErrorMessage( + e.message === 'invalid_credentials' + ? 'permission not granted' + : 'unknown error', + ); + throw e; + } + }, [ + callDeleteThread, + modalContext, + popThreadDeleteConfirmationModal, + setErrorMessage, + threadInfo.id, + ]); + + const dispatchDeleteThreadAction = React.useCallback(() => { + void dispatchActionPromise(deleteThreadActionTypes, deleteThreadAction()); + }, [dispatchActionPromise, deleteThreadAction]); + + const onDelete = React.useCallback( + (event: SyntheticEvent) => { + event.preventDefault(); + if (shouldUseDeleteConfirmationModal) { + modalContext.pushModal( + , + ); + } else { + dispatchDeleteThreadAction(); + } + }, + [ + dispatchDeleteThreadAction, + modalContext, + shouldUseDeleteConfirmationModal, + threadInfo, + ], + ); + + return onDelete; +} + +export { + useOnSaveGeneralThreadSettings, + useOnSavePrivacyThreadSettings, + useOnDeleteThread, +};