diff --git a/web/modals/threads/thread-settings-general-tab.react.js b/web/modals/threads/thread-settings-general-tab.react.js --- a/web/modals/threads/thread-settings-general-tab.react.js +++ b/web/modals/threads/thread-settings-general-tab.react.js @@ -2,36 +2,73 @@ import * as React from 'react'; +import { type SetState } from 'lib/types/hook-types.js'; +import { type ThreadInfo, type ThreadChanges } from 'lib/types/thread-types'; +import { firstLine } from 'lib/utils/string-utils'; + import Input from '../input.react.js'; import ColorSelector from './color-selector.react.js'; import css from './thread-settings-general-tab.css'; type ThreadSettingsGeneralTabProps = { +inputDisabled: boolean, - +threadNameValue: string, + +threadInfo: ThreadInfo, +threadNamePlaceholder: string, - +threadNameOnChange: (event: SyntheticEvent<HTMLInputElement>) => void, - +threadDescriptionValue: string, - +threadDescriptionOnChange: ( - event: SyntheticEvent<HTMLTextAreaElement>, - ) => void, - +threadColorCurrentColor: string, - +threadColorOnColorSelection: (color: string) => void, + +queuedChanges: ThreadChanges, + +setQueuedChanges: SetState<ThreadChanges>, }; function ThreadSettingsGeneralTab( props: ThreadSettingsGeneralTabProps, ): React.Node { const { inputDisabled, - threadNameValue, + threadInfo, threadNamePlaceholder, - threadNameOnChange, - threadDescriptionValue, - threadDescriptionOnChange, - threadColorCurrentColor, - threadColorOnColorSelection, + queuedChanges, + setQueuedChanges, } = props; + const onChangeName = React.useCallback( + (event: SyntheticEvent<HTMLInputElement>) => { + const target = event.currentTarget; + setQueuedChanges( + Object.freeze({ + ...queuedChanges, + name: firstLine( + target.value !== threadInfo.name ? target.value : undefined, + ), + }), + ); + }, + [queuedChanges, setQueuedChanges, threadInfo.name], + ); + + const onChangeDescription = React.useCallback( + (event: SyntheticEvent<HTMLTextAreaElement>) => { + const target = event.currentTarget; + setQueuedChanges( + Object.freeze({ + ...queuedChanges, + description: + target.value !== threadInfo.description ? target.value : undefined, + }), + ); + }, + [queuedChanges, setQueuedChanges, threadInfo.description], + ); + + const onChangeColor = React.useCallback( + (color: string) => { + setQueuedChanges( + Object.freeze({ + ...queuedChanges, + color: color !== threadInfo.color ? color : undefined, + }), + ); + }, + [queuedChanges, setQueuedChanges, threadInfo.color], + ); + return ( <div> <div> @@ -39,9 +76,9 @@ <div className={css.form_content}> <Input type="text" - value={threadNameValue} + value={firstLine(queuedChanges.name ?? threadInfo.name)} placeholder={threadNamePlaceholder} - onChange={threadNameOnChange} + onChange={onChangeName} disabled={inputDisabled} /> </div> @@ -50,9 +87,9 @@ <div className={css.form_title}>Description</div> <div className={css.form_content}> <textarea - value={threadDescriptionValue} + value={queuedChanges.description ?? threadInfo.description ?? ''} placeholder="Thread description" - onChange={threadDescriptionOnChange} + onChange={onChangeDescription} disabled={inputDisabled} /> </div> @@ -60,8 +97,8 @@ <div className={css.edit_thread_color_container}> <div className={`${css.form_title} ${css.color_title}`}>Color</div> <ColorSelector - currentColor={threadColorCurrentColor} - onColorSelection={threadColorOnColorSelection} + currentColor={queuedChanges.color ?? threadInfo.color} + onColorSelection={onChangeColor} /> </div> </div> diff --git a/web/modals/threads/thread-settings-modal.react.js b/web/modals/threads/thread-settings-modal.react.js --- a/web/modals/threads/thread-settings-modal.react.js +++ b/web/modals/threads/thread-settings-modal.react.js @@ -24,7 +24,6 @@ useDispatchActionPromise, useServerCall, } from 'lib/utils/action-utils'; -import { firstLine } from 'lib/utils/string-utils'; import Button from '../../components/button.react'; import { useModalContext } from '../../modals/modal-provider.react'; @@ -110,49 +109,6 @@ [queuedChanges], ); - const onChangeName = React.useCallback( - (event: SyntheticEvent<HTMLInputElement>) => { - const target = event.currentTarget; - setQueuedChanges( - Object.freeze({ - ...queuedChanges, - name: firstLine( - target.value !== threadInfo?.name ? target.value : undefined, - ), - }), - ); - }, - [queuedChanges, threadInfo?.name], - ); - - const onChangeDescription = React.useCallback( - (event: SyntheticEvent<HTMLTextAreaElement>) => { - const target = event.currentTarget; - setQueuedChanges( - Object.freeze({ - ...queuedChanges, - description: - target.value !== threadInfo?.description - ? target.value - : undefined, - }), - ); - }, - [queuedChanges, threadInfo?.description], - ); - - const onChangeColor = React.useCallback( - (color: string) => { - setQueuedChanges( - Object.freeze({ - ...queuedChanges, - color: color !== threadInfo?.color ? color : undefined, - }), - ); - }, - [queuedChanges, threadInfo?.color], - ); - const onChangeThreadType = React.useCallback( (event: SyntheticEvent<HTMLInputElement>) => { const uiValue = assertThreadType( @@ -288,19 +244,10 @@ mainContent = ( <ThreadSettingsGeneralTab inputDisabled={inputDisabled} - threadNameValue={firstLine( - queuedChanges['name'] ?? threadInfo['name'], - )} + threadInfo={threadInfo} threadNamePlaceholder={namePlaceholder} - threadNameOnChange={onChangeName} - threadDescriptionValue={ - queuedChanges['description'] ?? threadInfo['description'] ?? '' - } - threadDescriptionOnChange={onChangeDescription} - threadColorCurrentColor={ - queuedChanges['color'] ?? threadInfo['color'] - } - threadColorOnColorSelection={onChangeColor} + queuedChanges={queuedChanges} + setQueuedChanges={setQueuedChanges} /> ); } else if (currentTabType === 'privacy') {