diff --git a/web/modals/threads/create/compose-subchannel-modal.css b/web/modals/threads/create/compose-subchannel-modal.css index 3fbfefe81..1b96bbd6a 100644 --- a/web/modals/threads/create/compose-subchannel-modal.css +++ b/web/modals/threads/create/compose-subchannel-modal.css @@ -1,30 +1,33 @@ div.modalHeader { padding: 15px; font-weight: var(--semi-bold); color: var(--compose-subchannel-header-fg); background-color: var(--compose-subchannel-header-bg); display: flex; align-items: center; justify-content: center; margin-top: 30px; + column-gap: 10px; } div.modalHeaderParentName { color: var(--compose-subchannel-mark-color); - display: inline; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } div.container { width: 383px; overflow-y: auto; } div.stepContainer { position: relative; height: 100vh; max-height: 533px; } div.stepItem { padding: 20px; } diff --git a/web/modals/threads/create/compose-subchannel-modal.react.js b/web/modals/threads/create/compose-subchannel-modal.react.js index 801ca637f..ead3aff1b 100644 --- a/web/modals/threads/create/compose-subchannel-modal.react.js +++ b/web/modals/threads/create/compose-subchannel-modal.react.js @@ -1,283 +1,281 @@ // @flow import * as React from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { newThread, newThreadActionTypes } from 'lib/actions/thread-actions.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import type { ThreadInfo } from 'lib/types/thread-types.js'; import { threadTypes } from 'lib/types/thread-types.js'; import { useDispatchActionPromise, useServerCall, } from 'lib/utils/action-utils.js'; import { useResolvedThreadInfo } from 'lib/utils/entity-helpers.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 SubchannelSettings from './steps/subchannel-settings.react.js'; import type { VisibilityType } from './steps/subchannel-settings.react.js'; import Stepper from '../../../components/stepper.react.js'; import { updateNavInfoActionType } from '../../../redux/action-types.js'; import { nonThreadCalendarQuery } from '../../../selectors/nav-selectors.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}
-
+
{'within '}
+
{parentThreadName}
); } const createSubchannelLoadingStatusSelector = createLoadingStatusSelector(newThreadActionTypes); function ComposeSubchannelModal(props: Props): React.Node { const { parentThreadInfo, onClose } = props; 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;