diff --git a/web/sidebar/community-creation/community-creation-modal.css b/web/sidebar/community-creation/community-creation-modal.css --- a/web/sidebar/community-creation/community-creation-modal.css +++ b/web/sidebar/community-creation/community-creation-modal.css @@ -85,6 +85,13 @@ margin-top: 20px; } +div.createCommunityButtonContent { + display: flex; + justify-content: center; + align-items: center; + min-height: 24px; +} + .keyserverContainer { display: flex; justify-content: center; diff --git a/web/sidebar/community-creation/community-creation-modal.react.js b/web/sidebar/community-creation/community-creation-modal.react.js --- a/web/sidebar/community-creation/community-creation-modal.react.js +++ b/web/sidebar/community-creation/community-creation-modal.react.js @@ -1,16 +1,30 @@ // @flow import * as React from 'react'; +import { useDispatch } from 'react-redux'; +import { newThread, newThreadActionTypes } from 'lib/actions/thread-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; +import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; +import type { LoadingStatus } from 'lib/types/loading-types.js'; +import { threadTypes } from 'lib/types/thread-types-enum.js'; +import type { NewThreadResult } from 'lib/types/thread-types.js'; +import { + useDispatchActionPromise, + useServerCall, +} from 'lib/utils/action-utils.js'; import css from './community-creation-modal.css'; import CommIcon from '../../CommIcon.react.js'; -import Button from '../../components/button.react.js'; +import Button, { buttonThemes } from '../../components/button.react.js'; import EnumSettingsOption from '../../components/enum-settings-option.react.js'; import UserAvatar from '../../components/user-avatar.react.js'; +import LoadingIndicator from '../../loading-indicator.react.js'; import Input from '../../modals/input.react.js'; import Modal from '../../modals/modal.react.js'; +import { updateNavInfoActionType } from '../../redux/action-types.js'; +import { useSelector } from '../../redux/redux-utils.js'; +import { nonThreadCalendarQuery } from '../../selectors/nav-selectors.js'; const announcementStatements = [ { @@ -23,23 +37,80 @@ }, ]; +const createNewCommunityLoadingStatusSelector = + createLoadingStatusSelector(newThreadActionTypes); + function CommunityCreationModal(): React.Node { const modalContext = useModalContext(); + const dispatch = useDispatch(); + const dispatchActionPromise = useDispatchActionPromise(); + + const callNewThread = useServerCall(newThread); + const calendarQueryFunc = useSelector(nonThreadCalendarQuery); + + const [errorMessage, setErrorMessage] = React.useState(); + const [pendingCommunityName, setPendingCommunityName] = React.useState(''); const onChangePendingCommunityName = React.useCallback( - (event: SyntheticEvent) => - setPendingCommunityName(event.currentTarget.value), + (event: SyntheticEvent) => { + setErrorMessage(); + setPendingCommunityName(event.currentTarget.value); + }, [], ); const [announcementSetting, setAnnouncementSetting] = React.useState(false); const onAnnouncementSelected = React.useCallback(() => { + setErrorMessage(); setAnnouncementSetting(!announcementSetting); }, [announcementSetting]); + const callCreateNewCommunity = React.useCallback(async () => { + const calendarQuery = calendarQueryFunc(); + + try { + const newThreadResult: NewThreadResult = await callNewThread({ + name: pendingCommunityName, + type: announcementSetting + ? threadTypes.COMMUNITY_ANNOUNCEMENT_ROOT + : threadTypes.COMMUNITY_ROOT, + calendarQuery, + }); + return newThreadResult; + } catch (e) { + setErrorMessage('Community creation failed. Please try again.'); + throw e; + } + }, [ + announcementSetting, + calendarQueryFunc, + callNewThread, + pendingCommunityName, + ]); + + const createNewCommunity = React.useCallback(async () => { + setErrorMessage(); + + const newThreadResultPromise = callCreateNewCommunity(); + dispatchActionPromise(newThreadActionTypes, newThreadResultPromise); + const newThreadResult: NewThreadResult = await newThreadResultPromise; + + if (newThreadResult) { + const { newThreadID } = newThreadResult; + await dispatch({ + type: updateNavInfoActionType, + payload: { + activeChatThreadID: newThreadID, + }, + }); + + modalContext.popModal(); + } + }, [callCreateNewCommunity, dispatch, dispatchActionPromise, modalContext]); + const megaphoneIcon = React.useMemo( () => , [], @@ -55,6 +126,23 @@ ); } + const createNewCommunityLoadingStatus: LoadingStatus = useSelector( + createNewCommunityLoadingStatusSelector, + ); + let buttonContent; + if (createNewCommunityLoadingStatus === 'loading') { + buttonContent = ( + + ); + } else if (errorMessage) { + buttonContent = errorMessage; + } else { + buttonContent = 'Create community'; + } + return (
- +