2023-01-28 02:21:33 +01:00

211 lines
5.7 KiB
TypeScript

import type { FC } from '../../../lib/teact/teact';
import React, {
useState, useCallback, useEffect, memo,
} from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global';
import { ChatCreationProgress } from '../../../types';
import { selectTabState } from '../../../global/selectors';
import useLang from '../../../hooks/useLang';
import useHistoryBack from '../../../hooks/useHistoryBack';
import InputText from '../../ui/InputText';
import FloatingActionButton from '../../ui/FloatingActionButton';
import Spinner from '../../ui/Spinner';
import AvatarEditable from '../../ui/AvatarEditable';
import Button from '../../ui/Button';
import ListItem from '../../ui/ListItem';
import PrivateChatInfo from '../../common/PrivateChatInfo';
export type OwnProps = {
isChannel?: boolean;
isActive: boolean;
memberIds: string[];
onReset: (forceReturnToChatList?: boolean) => void;
};
type StateProps = {
creationProgress?: ChatCreationProgress;
creationError?: string;
maxGroupSize?: number;
};
const NewChatStep2: FC<OwnProps & StateProps > = ({
isChannel,
isActive,
memberIds,
maxGroupSize,
creationProgress,
creationError,
onReset,
}) => {
const {
createGroupChat,
createChannel,
} = getActions();
const lang = useLang();
useHistoryBack({
isActive,
onBack: onReset,
});
const [title, setTitle] = useState('');
const [about, setAbout] = useState('');
const [photo, setPhoto] = useState<File | undefined>();
const [error, setError] = useState<string | undefined>();
const chatTitleEmptyError = 'Chat title can\'t be empty';
const channelTitleEmptyError = 'Channel title can\'t be empty';
const chatTooManyUsersError = 'Sorry, creating supergroups is not yet supported';
const isLoading = creationProgress === ChatCreationProgress.InProgress;
const handleTitleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const { value } = e.currentTarget;
const newValue = value.replace(/^\s+/, '');
setTitle(newValue);
if (newValue !== value) {
e.currentTarget.value = newValue;
}
}, []);
const handleDescriptionChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
setAbout(e.currentTarget.value);
}, []);
const handleCreateGroup = useCallback(() => {
if (!title.length) {
setError(chatTitleEmptyError);
return;
}
if (maxGroupSize && memberIds.length >= maxGroupSize) {
setError(chatTooManyUsersError);
return;
}
createGroupChat({
title,
photo,
memberIds,
});
}, [title, memberIds, maxGroupSize, createGroupChat, photo]);
const handleCreateChannel = useCallback(() => {
if (!title.length) {
setError(channelTitleEmptyError);
return;
}
createChannel({
title,
about,
photo,
memberIds,
});
}, [title, createChannel, about, photo, memberIds, channelTitleEmptyError]);
useEffect(() => {
if (creationProgress === ChatCreationProgress.Complete) {
onReset(true);
}
}, [creationProgress, onReset]);
const renderedError = (creationError && lang(creationError)) || (
error !== chatTitleEmptyError && error !== channelTitleEmptyError
? error
: undefined
);
return (
<div className="NewChat">
<div className="left-header">
<Button
round
size="smaller"
color="translucent"
// eslint-disable-next-line react/jsx-no-bind
onClick={() => onReset()}
ariaLabel="Return to member selection"
>
<i className="icon-arrow-left" />
</Button>
<h3>{lang(isChannel ? 'NewChannel' : 'NewGroup')}</h3>
</div>
<div className="NewChat-inner step-2">
<AvatarEditable
onChange={setPhoto}
title={lang('AddPhoto')}
/>
<InputText
value={title}
onChange={handleTitleChange}
label={lang(isChannel ? 'EnterChannelName' : 'GroupName')}
error={error === chatTitleEmptyError || error === channelTitleEmptyError ? error : undefined}
/>
{isChannel && (
<>
<InputText
value={about}
onChange={handleDescriptionChange}
label={lang('DescriptionOptionalPlaceholder')}
/>
<p className="note">{lang('DescriptionInfo')}</p>
</>
)}
{renderedError && (
<p className="error">{renderedError}</p>
)}
{memberIds.length > 0 && (
<>
<h3 className="chat-members-heading">{lang('GroupInfo.ParticipantCount', memberIds.length, 'i')}</h3>
<div className="chat-members-list custom-scroll">
{memberIds.map((id) => (
<ListItem inactive className="chat-item-clickable">
<PrivateChatInfo userId={id} />
</ListItem>
))}
</div>
</>
)}
</div>
<FloatingActionButton
isShown={title.length !== 0}
onClick={isChannel ? handleCreateChannel : handleCreateGroup}
disabled={isLoading}
ariaLabel={isChannel ? lang('ChannelIntro.CreateChannel') : 'Create Group'}
>
{isLoading ? (
<Spinner color="white" />
) : (
<i className="icon-arrow-right" />
)}
</FloatingActionButton>
</div>
);
};
export default memo(withGlobal<OwnProps>(
(global): StateProps => {
const {
progress: creationProgress,
error: creationError,
} = selectTabState(global).chatCreation || {};
return {
creationProgress,
creationError,
maxGroupSize: global.config?.maxGroupSize,
};
},
)(NewChatStep2));