diff --git a/web/modals/threads/create/compose-subchannel-modal.react.js b/web/modals/threads/create/compose-subchannel-modal.react.js index 0bc2cf5f5..be3306d31 100644 --- a/web/modals/threads/create/compose-subchannel-modal.react.js +++ b/web/modals/threads/create/compose-subchannel-modal.react.js @@ -1,284 +1,285 @@ // @flow import * as React from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { newThread, newThreadActionTypes } from 'lib/actions/thread-actions'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors'; import type { ThreadInfo } from 'lib/types/thread-types'; import { threadTypes } from 'lib/types/thread-types'; import { useDispatchActionPromise, useServerCall, } from 'lib/utils/action-utils'; +import { useResolvedThreadInfo } from 'lib/utils/entity-helpers'; import { trimText } from 'lib/utils/text-utils'; import Stepper from '../../../components/stepper.react'; import { updateNavInfoActionType } from '../../../redux/action-types'; import { nonThreadCalendarQuery } from '../../../selectors/nav-selectors'; import Modal from '../../modal.react'; import css from './compose-subchannel-modal.css'; import SubchannelMembers from './steps/subchannel-members.react'; import SubchannelSettings from './steps/subchannel-settings.react'; import type { VisibilityType } from './steps/subchannel-settings.react'; type Props = { +onClose: () => void, +parentThreadInfo: ThreadInfo, }; const getThreadType = (visibility: VisibilityType, announcement: boolean) => { if (visibility === 'open') { return announcement ? threadTypes.COMMUNITY_OPEN_ANNOUNCEMENT_SUBTHREAD : threadTypes.COMMUNITY_OPEN_SUBTHREAD; } else { return announcement ? threadTypes.COMMUNITY_SECRET_ANNOUNCEMENT_SUBTHREAD : threadTypes.COMMUNITY_SECRET_SUBTHREAD; } }; type Steps = 'settings' | 'members'; type HeaderProps = { +parentThreadName: string, }; function ComposeSubchannelHeader(props: HeaderProps): React.Node { const { parentThreadName } = props; return (
{'within '}
{parentThreadName}
); } const createSubchannelLoadingStatusSelector = createLoadingStatusSelector( newThreadActionTypes, ); function ComposeSubchannelModal(props: Props): React.Node { const { parentThreadInfo, onClose } = props; - const { uiName: parentThreadName } = parentThreadInfo; + const { uiName: parentThreadName } = useResolvedThreadInfo(parentThreadInfo); const [activeStep, setActiveStep] = React.useState('settings'); const [channelName, setChannelName] = React.useState(''); const [visibilityType, setVisibilityType] = React.useState( 'open', ); const [announcement, setAnnouncement] = React.useState(false); const [selectedUsers, setSelectedUsers] = React.useState< $ReadOnlySet, >(new Set()); const [searchUserText, setSearchUserText] = React.useState(''); const loadingState = useSelector(createSubchannelLoadingStatusSelector); const [errorMessage, setErrorMessage] = React.useState(''); const calendarQuery = useSelector(nonThreadCalendarQuery); const callNewThread = useServerCall(newThread); const dispatchActionPromise = useDispatchActionPromise(); const dispatch = useDispatch(); const createSubchannel = React.useCallback(async () => { try { const threadType = getThreadType(visibilityType, announcement); const query = calendarQuery(); const result = await callNewThread({ name: channelName, type: threadType, parentThreadID: parentThreadInfo.id, initialMemberIDs: Array.from(selectedUsers), calendarQuery: query, color: parentThreadInfo.color, }); return result; } catch (e) { await setErrorMessage( e.message === 'invalid_parameters' && announcement ? 'announcement channels currently not available' : 'unknown error', ); return null; } }, [ parentThreadInfo, selectedUsers, visibilityType, announcement, callNewThread, calendarQuery, channelName, ]); const dispatchCreateSubchannel = React.useCallback(async () => { await setErrorMessage(''); const response = createSubchannel(); await dispatchActionPromise(newThreadActionTypes, response); const result = await response; if (result) { const { newThreadID } = result; await dispatch({ type: updateNavInfoActionType, payload: { activeChatThreadID: newThreadID, }, }); props.onClose(); } }, [dispatchActionPromise, createSubchannel, props, dispatch]); const onChangeChannelName = React.useCallback( (event: SyntheticEvent) => { const target = event.currentTarget; setChannelName(target.value); }, [], ); const onOpenVisibilityTypeSelected = React.useCallback( () => setVisibilityType('open'), [], ); const onSecretVisibilityTypeSelected = React.useCallback( () => setVisibilityType('secret'), [], ); const onAnnouncementSelected = React.useCallback( () => setAnnouncement(!announcement), [announcement], ); const toggleUserSelection = React.useCallback((userID: string) => { setSelectedUsers((users: $ReadOnlySet) => { const newUsers = new Set(users); if (newUsers.has(userID)) { newUsers.delete(userID); } else { newUsers.add(userID); } return newUsers; }); }, []); const subchannelSettings = React.useMemo( () => ( ), [ channelName, visibilityType, announcement, onChangeChannelName, onOpenVisibilityTypeSelected, onSecretVisibilityTypeSelected, onAnnouncementSelected, ], ); const stepperButtons = React.useMemo( () => ({ settings: { nextProps: { content: 'Next', disabled: !channelName.trim(), onClick: () => { setErrorMessage(''); setChannelName(channelName.trim()); setActiveStep('members'); }, }, }, members: { prevProps: { content: 'Back', onClick: () => setActiveStep('settings'), }, nextProps: { content: 'Create', loading: loadingState === 'loading', disabled: selectedUsers.size === 0, onClick: () => { dispatchCreateSubchannel(); }, }, }, }), [channelName, dispatchCreateSubchannel, loadingState, selectedUsers], ); const subchannelMembers = React.useMemo( () => ( ), [ selectedUsers, toggleUserSelection, parentThreadInfo, searchUserText, setSearchUserText, ], ); const modalName = activeStep === 'members' ? `Create channel - ${trimText(channelName, 11)}` : 'Create channel'; return (
); } export default ComposeSubchannelModal;