cinny/src/app/organisms/create-channel/CreateChannel.jsx
2021-07-28 18:45:52 +05:30

165 lines
6.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useRef } from 'react';
import PropTypes from 'prop-types';
import './CreateChannel.scss';
import initMatrix from '../../../client/initMatrix';
import { isRoomAliasAvailable } from '../../../util/matrixUtil';
import * as roomActions from '../../../client/action/room';
import Text from '../../atoms/text/Text';
import Button from '../../atoms/button/Button';
import Toggle from '../../atoms/button/Toggle';
import IconButton from '../../atoms/button/IconButton';
import Input from '../../atoms/input/Input';
import Spinner from '../../atoms/spinner/Spinner';
import PopupWindow from '../../molecules/popup-window/PopupWindow';
import SettingTile from '../../molecules/setting-tile/SettingTile';
import HashPlusIC from '../../../../public/res/ic/outlined/hash-plus.svg';
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
function CreateChannel({ isOpen, onRequestClose }) {
const [isPublic, togglePublic] = useState(false);
const [isEncrypted, toggleEncrypted] = useState(true);
const [isValidAddress, updateIsValidAddress] = useState(null);
const [isCreatingRoom, updateIsCreatingRoom] = useState(false);
const [creatingError, updateCreatingError] = useState(null);
const [titleValue, updateTitleValue] = useState(undefined);
const [topicValue, updateTopicValue] = useState(undefined);
const [addressValue, updateAddressValue] = useState(undefined);
const addressRef = useRef(null);
const topicRef = useRef(null);
const nameRef = useRef(null);
const userId = initMatrix.matrixClient.getUserId();
const hsString = userId.slice(userId.indexOf(':'));
function resetForm() {
togglePublic(false);
toggleEncrypted(true);
updateIsValidAddress(null);
updateIsCreatingRoom(false);
updateCreatingError(null);
updateTitleValue(undefined);
updateTopicValue(undefined);
updateAddressValue(undefined);
}
async function createRoom() {
if (isCreatingRoom) return;
updateIsCreatingRoom(true);
updateCreatingError(null);
const name = nameRef.current.value;
let topic = topicRef.current.value;
if (topic.trim() === '') topic = undefined;
let roomAlias;
if (isPublic) {
roomAlias = addressRef?.current?.value;
if (roomAlias.trim() === '') roomAlias = undefined;
}
try {
await roomActions.create({
name, topic, isPublic, roomAlias, isEncrypted,
});
resetForm();
onRequestClose();
} catch (e) {
if (e.message === 'M_UNKNOWN: Invalid characters in room alias') {
updateCreatingError('ERROR: Invalid characters in channel address');
updateIsValidAddress(false);
} else if (e.message === 'M_ROOM_IN_USE: Room alias already taken') {
updateCreatingError('ERROR: Channel address is already in use');
updateIsValidAddress(false);
} else updateCreatingError(e.message);
}
updateIsCreatingRoom(false);
}
function validateAddress(e) {
const myAddress = e.target.value;
updateIsValidAddress(null);
updateAddressValue(e.target.value);
updateCreatingError(null);
setTimeout(async () => {
if (myAddress !== addressRef.current.value) return;
const roomAlias = addressRef.current.value;
if (roomAlias === '') return;
const roomAddress = `#${roomAlias}${hsString}`;
if (await isRoomAliasAvailable(roomAddress)) {
updateIsValidAddress(true);
} else {
updateIsValidAddress(false);
}
}, 1000);
}
function handleTitleChange(e) {
if (e.target.value.trim() === '') updateTitleValue(undefined);
updateTitleValue(e.target.value);
}
function handleTopicChange(e) {
if (e.target.value.trim() === '') updateTopicValue(undefined);
updateTopicValue(e.target.value);
}
return (
<PopupWindow
isOpen={isOpen}
title="Create channel"
contentOptions={<IconButton src={CrossIC} onClick={onRequestClose} tooltip="Close" />}
onRequestClose={onRequestClose}
>
<div className="create-channel">
<form className="create-channel__form" onSubmit={(e) => { e.preventDefault(); createRoom(); }}>
<SettingTile
title="Make channel public"
options={<Toggle isActive={isPublic} onToggle={togglePublic} />}
content={<Text variant="b3">Public channel can be joined by anyone.</Text>}
/>
{isPublic && (
<div>
<Text className="create-channel__address__label" variant="b2">Channel address</Text>
<div className="create-channel__address">
<Text variant="b1">#</Text>
<Input value={addressValue} onChange={validateAddress} state={(isValidAddress === false) ? 'error' : 'normal'} forwardRef={addressRef} placeholder="my_room" required />
<Text variant="b1">{hsString}</Text>
</div>
{isValidAddress === false && <Text className="create-channel__address__tip" variant="b3"><span style={{ color: 'var(--bg-danger)' }}>{`#${addressValue}${hsString} is already in use`}</span></Text>}
</div>
)}
{!isPublic && (
<SettingTile
title="Enable end-to-end encryption"
options={<Toggle isActive={isEncrypted} onToggle={toggleEncrypted} />}
content={<Text variant="b3">You cant disable this later. Bridges & most bots wont work yet.</Text>}
/>
)}
<Input value={topicValue} onChange={handleTopicChange} forwardRef={topicRef} minHeight={174} resizable label="Topic (optional)" />
<div className="create-channel__name-wrapper">
<Input value={titleValue} onChange={handleTitleChange} forwardRef={nameRef} label="Channel name" required />
<Button disabled={isValidAddress === false || isCreatingRoom} iconSrc={HashPlusIC} type="submit" variant="primary">Create</Button>
</div>
{isCreatingRoom && (
<div className="create-channel__loading">
<Spinner size="small" />
<Text>Creating channel...</Text>
</div>
)}
{typeof creatingError === 'string' && <Text className="create-channel__error" variant="b3">{creatingError}</Text>}
</form>
</div>
</PopupWindow>
);
}
CreateChannel.propTypes = {
isOpen: PropTypes.bool.isRequired,
onRequestClose: PropTypes.func.isRequired,
};
export default CreateChannel;