diff --git a/web/modals/threads/settings/thread-settings-delete-tab.react.js b/web/modals/threads/settings/thread-settings-delete-tab.react.js index 866c2dcd1..3be4c34b2 100644 --- a/web/modals/threads/settings/thread-settings-delete-tab.react.js +++ b/web/modals/threads/settings/thread-settings-delete-tab.react.js @@ -1,117 +1,121 @@ // @flow import * as React from 'react'; import { deleteThreadActionTypes, deleteThread, } from 'lib/actions/thread-actions'; import { type SetState } from 'lib/types/hook-types'; import { type ThreadInfo } from 'lib/types/thread-types'; import { useDispatchActionPromise, useServerCall, } from 'lib/utils/action-utils'; import Button from '../../../components/button.react'; import SWMansionIcon from '../../../SWMansionIcon.react'; import Input from '../../input.react'; import { useModalContext } from '../../modal-provider.react'; import css from './thread-settings-delete-tab.css'; type ThreadSettingsDeleteTabProps = { - +inputDisabled: boolean, + +threadSettingsOperationInProgress: boolean, +threadInfo: ThreadInfo, +setErrorMessage: SetState, }; function ThreadSettingsDeleteTab( props: ThreadSettingsDeleteTabProps, ): React.Node { - const { inputDisabled, threadInfo, setErrorMessage } = props; + const { + threadSettingsOperationInProgress, + threadInfo, + setErrorMessage, + } = props; const modalContext = useModalContext(); const dispatchActionPromise = useDispatchActionPromise(); const callDeleteThread = useServerCall(deleteThread); const accountPasswordInputRef = React.useRef(); const [accountPassword, setAccountPassword] = React.useState(''); const onChangeAccountPassword = React.useCallback( (event: SyntheticEvent) => { const target = event.currentTarget; setAccountPassword(target.value); }, [], ); const deleteThreadAction = React.useCallback(async () => { try { const response = await callDeleteThread(threadInfo.id, accountPassword); modalContext.popModal(); return response; } catch (e) { setErrorMessage( e.message === 'invalid_credentials' ? 'wrong password' : 'unknown error', ); setAccountPassword(''); accountPasswordInputRef.current?.focus(); throw e; } }, [ accountPassword, callDeleteThread, modalContext, setAccountPassword, setErrorMessage, threadInfo.id, ]); const onDelete = React.useCallback( (event: SyntheticEvent) => { event.preventDefault(); dispatchActionPromise(deleteThreadActionTypes, deleteThreadAction()); }, [deleteThreadAction, dispatchActionPromise], ); return (

Your thread will be permanently deleted. There is no way to reverse this.

Please enter your account password to confirm your identity.

Account password
); } export default ThreadSettingsDeleteTab; diff --git a/web/modals/threads/settings/thread-settings-general-tab.react.js b/web/modals/threads/settings/thread-settings-general-tab.react.js index 51a2205a3..3d475d51e 100644 --- a/web/modals/threads/settings/thread-settings-general-tab.react.js +++ b/web/modals/threads/settings/thread-settings-general-tab.react.js @@ -1,190 +1,192 @@ // @flow import * as React from 'react'; import tinycolor from 'tinycolor2'; import { changeThreadSettingsActionTypes, changeThreadSettings, } from 'lib/actions/thread-actions'; import { threadHasPermission } from 'lib/shared/thread-utils'; import { type SetState } from 'lib/types/hook-types'; import { type ThreadInfo, type ThreadChanges, threadPermissions, } from 'lib/types/thread-types'; import { useDispatchActionPromise, useServerCall, } from 'lib/utils/action-utils'; import { firstLine } from 'lib/utils/string-utils'; import Button from '../../../components/button.react'; import Input from '../../input.react'; import { useModalContext } from '../../modal-provider.react'; import ColorSelector from '../color-selector.react'; import css from './thread-settings-general-tab.css'; type ThreadSettingsGeneralTabProps = { - +inputDisabled: boolean, + +threadSettingsOperationInProgress: boolean, +threadInfo: ThreadInfo, +threadNamePlaceholder: string, +queuedChanges: ThreadChanges, +setQueuedChanges: SetState, +setErrorMessage: SetState, }; function ThreadSettingsGeneralTab( props: ThreadSettingsGeneralTabProps, ): React.Node { const { - inputDisabled, + threadSettingsOperationInProgress, threadInfo, threadNamePlaceholder, queuedChanges, setQueuedChanges, setErrorMessage, } = props; const modalContext = useModalContext(); const dispatchActionPromise = useDispatchActionPromise(); const callChangeThreadSettings = useServerCall(changeThreadSettings); const nameInputRef = React.useRef(); React.useEffect(() => { nameInputRef.current?.focus(); - }, [inputDisabled]); + }, [threadSettingsOperationInProgress]); const changeQueued: boolean = React.useMemo( () => Object.values(queuedChanges).some(v => v !== null && v !== undefined), [queuedChanges], ); const onChangeName = React.useCallback( (event: SyntheticEvent) => { const target = event.currentTarget; const newName = firstLine(target.value); setQueuedChanges(prevQueuedChanges => Object.freeze({ ...prevQueuedChanges, name: newName !== threadInfo.name ? newName : undefined, }), ); }, [setQueuedChanges, threadInfo.name], ); const onChangeDescription = React.useCallback( (event: SyntheticEvent) => { const target = event.currentTarget; setQueuedChanges(prevQueuedChanges => Object.freeze({ ...prevQueuedChanges, description: target.value !== threadInfo.description ? target.value : undefined, }), ); }, [setQueuedChanges, threadInfo.description], ); const onChangeColor = React.useCallback( (color: string) => { setQueuedChanges(prevQueuedChanges => Object.freeze({ ...prevQueuedChanges, color: !tinycolor.equals(color, threadInfo.color) ? color : undefined, }), ); }, [setQueuedChanges, threadInfo.color], ); const changeThreadSettingsAction = React.useCallback(async () => { try { 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(); dispatchActionPromise( changeThreadSettingsActionTypes, changeThreadSettingsAction(), ); }, [changeThreadSettingsAction, dispatchActionPromise], ); const threadNameInputDisabled = !threadHasPermission( threadInfo, threadPermissions.EDIT_THREAD_NAME, ); return (
Thread name
Description