diff --git a/web/modals/threads/create/compose-subchannel-modal.react.js b/web/modals/threads/create/compose-subchannel-modal.react.js index b3e80b75e..bb5b4b7b4 100644 --- a/web/modals/threads/create/compose-subchannel-modal.react.js +++ b/web/modals/threads/create/compose-subchannel-modal.react.js @@ -1,293 +1,292 @@ // @flow import * as React from 'react'; import { newThreadActionTypes, useNewThinThread, } from 'lib/actions/thread-actions.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { threadTypes } from 'lib/types/thread-types-enum.js'; import { useResolvedThreadInfo } from 'lib/utils/entity-helpers.js'; import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import { useDispatch } from 'lib/utils/redux-utils.js'; import { trimText } from 'lib/utils/text-utils.js'; import css from './compose-subchannel-modal.css'; import SubchannelMembers from './steps/subchannel-members.react.js'; import type { VisibilityType } from './steps/subchannel-settings.react.js'; import SubchannelSettings from './steps/subchannel-settings.react.js'; import Button from '../../../components/button.react.js'; import { updateNavInfoActionType } from '../../../redux/action-types.js'; import { useSelector } from '../../../redux/redux-utils.js'; import { nonThreadCalendarQuery } from '../../../selectors/nav-selectors.js'; import { useAddUsersListContext, AddUsersListProvider, } from '../../../settings/relationship/add-users-list-provider.react.js'; import Modal from '../../modal.react.js'; 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 } = useResolvedThreadInfo(parentThreadInfo); const { pendingUsersToAdd } = useAddUsersListContext(); const [activeStep, setActiveStep] = React.useState('settings'); const [channelName, setChannelName] = React.useState(''); const [visibilityType, setVisibilityType] = React.useState('open'); const [announcement, setAnnouncement] = React.useState(false); const loadingState = useSelector(createSubchannelLoadingStatusSelector); const [errorMessage, setErrorMessage] = React.useState(''); const calendarQuery = useSelector(nonThreadCalendarQuery); const callNewThinThread = useNewThinThread(); const dispatchActionPromise = useDispatchActionPromise(); const dispatch = useDispatch(); const threadType = getThreadType(visibilityType, announcement); const createSubchannel = React.useCallback(async () => { try { const query = calendarQuery(); const result = await callNewThinThread({ name: channelName, type: threadType, parentThreadID: parentThreadInfo.id, initialMemberIDs: Array.from(pendingUsersToAdd.keys()), calendarQuery: query, color: parentThreadInfo.color, }); return result; } catch (e) { await setErrorMessage('unknown error'); return null; } }, [ calendarQuery, callNewThinThread, channelName, threadType, parentThreadInfo.id, parentThreadInfo.color, pendingUsersToAdd, ]); 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 subchannelSettings = React.useMemo( () => ( ), [ channelName, visibilityType, announcement, onChangeChannelName, onOpenVisibilityTypeSelected, onSecretVisibilityTypeSelected, onAnnouncementSelected, ], ); const subchannelMembers = React.useMemo( () => ( ), [parentThreadInfo, threadType], ); const modalName = activeStep === 'members' ? `Create channel - ${trimText(channelName, 11)}` : 'Create channel'; const subheader = React.useMemo( () => , [parentThreadName], ); const modalContent = React.useMemo(() => { if (activeStep === 'settings') { return subchannelSettings; } return subchannelMembers; }, [activeStep, subchannelMembers, subchannelSettings]); const onClickNext = React.useCallback(() => { setErrorMessage(''); setChannelName(channelName.trim()); setActiveStep('members'); }, [channelName]); const primaryButton = React.useMemo(() => { if (activeStep === 'settings') { return ( ); } return ( ); }, [ activeStep, channelName, dispatchCreateSubchannel, loadingState, onClickNext, - pendingUsersToAdd.size, ]); const onClickBack = React.useCallback(() => setActiveStep('settings'), []); const secondaryButton = React.useMemo(() => { if (activeStep !== 'members') { return null; } return ( ); }, [activeStep, onClickBack]); return (
{modalContent} {errorMessage}
); } function ComposeSubchannelModalWrapper(props: Props): React.Node { const composeSubchannelModalWrapper = React.useMemo( () => ( ), [props], ); return composeSubchannelModalWrapper; } export default ComposeSubchannelModalWrapper;